Конечно можно вставлять в код самого приложения обычные условные операторы, проверяющие версию,.. но почему обязательно хотите избежать #директив препроцессора, фактически он для таких вещей и создавался!
Не хотите пользоваться штатным препроцессором - пилите свой, который будет под нужную версию подготавливать проект для сборки, буквально собирая его из файлов. Т.е. это будет приложение (простенькие скрипты и какое-то описание файлов проекта) которое вы будете запускать для создания релиза.