Указатель на функцию:
плюсы: явный механизм (требует явных действий пользователя - вызова функции регистрации нового callback), понятней и проще (реализован стандартными средствами языка), универсальней (будет работать на всех платформах и компиляторах), для подключения пользовательского функционала не требуется пересборка библиотеки.
минусы: динамическое связывание - если функция будет активно вызываться, то это может привести к дополнительным накладным расходам.
weak:
плюсы: статическое связывание (отсутствие накладных расходов на вызов)
минусы: требуется не стандартная поддержка компилятора (может не работать при использовании другого компилятора, например у компилятора микрософт другой синтаксис для этого), связывание происходит не явно (компилятор сам выбирает какую функцию использовать из подходящих вариантов), для подключения пользовательского функционала требуется пересборка библиотеки
Условная компиляция:
плюсы: статическое связывание (отсутствие накладных расходов на вызов), универсальность, явный механизм
минусы: возможно немного сложней в реализации, чем weak, для подключения пользовательского функционала требуется пересборка библиотеки
Выводы:
Если требуется статическое связывание, то выбор - условная компиляция. При грамотной реализации тут можно минимизировать действия пользователя по подключению своей реализации функции в сборку библиотеки. Если библиотеку не планируется выпускать в открытый доступ и не смущает не стандартность - можно использовать weak из-за простоты реализации.
В остальных случаях - указатель на функцию.