Отменить флаги компиляции для отдельных файлов

110

Я хотел бы использовать глобальный набор флагов для компиляции проекта, что означает, что в моем файле CMakeLists.txt верхнего уровня я указал:

ADD_DEFINITIONS ( -Wall -Weffc++ -pedantic -std=c++0x )

Однако для конкретного файла (скажем, «foo.cpp») в подкаталоге я хочу отключить флаги компиляции, чтобы не применять -Weffc ++ (включенная коммерческая библиотека, которую я не могу изменить). Чтобы упростить ситуацию использовать только -Wall, я попробовал:

 SET_SOURCE_FILES_PROPERTIES( foo.cpp PROPERTIES COMPILE_FLAGS -Wall )
 ADD_EXECUTABLE( foo foo.cpp )

, что не сработало. Я тоже пробовал

SET_PROPERTY( SOURCE foo.cpp PROPERTY COMPILE_FLAGS -Wall )
ADD_EXECUTABLE( foo foo.cpp )

и

ADD_EXECUTABLE( foo foo.cpp )
SET_TARGET_PROPERTIES( foo PROPERTIES COMPILE_FLAGS -Wall )

, в котором ни один из них не работал.

Наконец, я попытался удалить это определение:

REMOVE_DEFINITIONS( -Weffc++ )
ADD_EXECUTABLE( foo foo.cpp )
ADD_DEFINITIONS( -Weffc++ )

, что также не сработало (то есть я получаю много предупреждений о стилях коммерческой библиотеки). (** Примечание: предупреждения ПОДАВАЮТСЯ, если Я НЕ повторно включаю директиву -Weffc ++ после сборки исполняемого файла.)

Я также попытался временно удалить флаги компиляции: http://www.cmake.org/pipermail/cmake/2007-June/014614.html , но это не помогло.

Разве это не изящное решение?

JB Браун
источник
1
Подождите, если ваша последняя попытка сработает, но только после ее создания, может это не проблема кеширования? Попробуйте удалить CMakeCache после внесения изменений.
Кэмерон
По теме см. Как изменить флаг компилятора только для одного исполняемого файла в CMake? Ответ Андре показывает способ заменить существующие параметры новыми.
jww

Ответы:

126

Ваши попытки выше добавляют дополнительные флаги к вашему файлу / цели, а не перезаписывают, как вы, кажется, ожидаете. Например, из документации по свойствам исходных файлов - COMPILE_FLAGS :

Эти флаги будут добавлены в список флагов компиляции при сборке этого исходного файла.

Вы должны иметь возможность отменить -Weffc++флаг для foo.cpp, выполнив

set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -Wno-effc++)

Это должно иметь эффект добавления -Wno-effc++после -Weffc++в команде компилятора, и последний параметр выигрывает. Чтобы увидеть полную команду и убедиться, что это действительно так, вы можете сделать

make VERBOSE=1

Кстати, один из разработчиков стандартной библиотеки GNU C ++ высказывает довольно отрицательное мнение -Weffc++в этом ответе .

Другой момент заключается в том, что вы злоупотребляете add_definitionsв том смысле, что используете это для флагов компилятора, а не для предполагаемых определений препроцессора.

Было бы предпочтительнее использовать add_compile_options

add_compile_options(-Wall -Weffc++ -pedantic -std=c++0x)

или для версий CMake <3.0, чтобы сделать что-то вроде:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Weffc++ -pedantic -std=c++0x")

Отвечая на дополнительные вопросы в комментариях ниже, я считаю, что невозможно надежно удалить флаг в одном файле. Причина в том, что для любого исходного файла он имеет COMPILE_OPTIONSиCOMPILE_FLAGS 1 его целевого объекта, но они не отображаются ни в одном из свойств этого исходного файла.

Вы могли бы посмотреть, как убрать флаг проблемы с целевой COMPILE_OPTIONS , а затем применить его к каждому из целевых источников по отдельности, при необходимости исключив его из конкретного исходного файла.

Однако, хотя это может работать во многих сценариях, у него есть несколько проблем.

Во-первых, свойства исходных файлов не включают COMPILE_OPTIONS, только COMPILE_FLAGS. Это проблема, потому что COMPILE_OPTIONSцель может включать выражения генератора , ноCOMPILE_FLAGS не поддерживает их. Таким образом, вам придется использовать выражения генератора при поиске вашего флага, и вам, возможно, даже придется «анализировать» выражения генератора, если ваш флаг содержится в одном или нескольких, чтобы увидеть, следует ли его повторно применить к оставшимся исходные файлы.

Во-вторых, начиная с CMake v3.0, цели могут указывать INTERFACE_COMPILE_OPTIONS. Это означает, что зависимость вашей цели может добавлять или переопределять вашу цель COMPILE_OPTIONSчерез свои INTERFACE_COMPILE_OPTIONS. Таким образом, вам также придется рекурсивно перебирать все зависимости вашей цели (не особенно простая задача, поскольку список LINK_LIBRARIESдля цели также может содержать выражения генератора), чтобы найти любые, которые применяют флаг проблемы, и попытаться удалить его из тех цели INTERFACE_COMPILE_OPTIONSтоже.

На этом этапе сложности я хотел бы отправить патч в CMake, чтобы обеспечить функциональность для безоговорочного удаления определенного флага из исходного файла.


1: Обратите внимание, что, в отличие от COMPILE_FLAGSсвойства исходных файлов, COMPILE_FLAGSсвойство целевых объектов устарело.

Fraser
источник
6
Но как на самом деле установить флаги компиляции для файлов отдельно, не добавляя их? Например, я хочу использовать разные флаги компиляции для результирующей цели, чем для файлов, но поскольку они добавлены, мне пришлось бы удалить их вручную. Нет ли свойства, которое не добавляется, а фактически устанавливает их только для указанного файла / цели?
Baradé
2
Что мы можем сделать, если -fno-flag недоступен (и установлен -fflag)?
gnzlbg 05
@ Baradé Вы не можете - не для исходного файла.
Fraser
@gnzlbg Опять же, мы в значительной степени застряли. Я обновил свой ответ, чтобы дать немного больше информации (и возможный обходной путь, который, вероятно, сработает в некоторых сценариях).
Fraser
Действительно ли нет обходного пути для настройки параметров компиляции одного файла? Мне нужно отключить создание покрытия gcc для некоторых файлов, которые вызывают сбой gcov.
Lothar
5

Просто добавив к правильному ответу @Fraser.

В случае, если вы хотите добавить специальный флаг в определенные папки, вы можете сделать:

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_property(SOURCE ${SPECIAL_SRC_FILES} PROPERTY COMPILE_FLAGS -Wno-effc++)

или

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_source_files_properties(${SPECIAL_SRC_FILES} PROPERTIES COMPILE_FLAGS -Wno-effc++)

Обратите внимание, что не рекомендуется использовать GLOB, как обсуждается здесь

Левон
источник
0

Используя ответ @Fraser, я создал следующее для обработки включений Qt, потому что переменная включает несколько путей, разделенных точкой с запятой. Это означает, что мне пришлось сначала добавить foreach()цикл и вручную создать флаги включения . Но это позволяет мне иметь одно исключение: foo.cpp (этот файл сейчас использует Qt, но в долгосрочной перспективе я хочу удалить эту зависимость, и я хочу убедиться, что Qt не закрадывается в другое место).

find_package(Qt5Core REQUIRED)
set(QT_INCLUDE_PROPERTIES "")
foreach(DIR ${Qt5Core_INCLUDE_DIRS})
    set(QT_INCLUDE_PROPERTIES "${QT_INCLUDE_PROPERTIES} -isystem ${DIR}")
endforeach()
set_source_files_properties(foo.cpp PROPERTIES
    COMPILE_FLAGS
        ${QT_INCLUDE_PROPERTIES}
)

Также обратите внимание, что я использую -isystemвместо, -Iчтобы избежать некоторых предупреждений, которые в противном случае генерируются заголовками Qt (у меня включена масса предупреждений).

Алексис Вилке
источник