Заміна компіляції прапорів для окремих файлів


109

Я хотів би використовувати глобальний набір прапорів для складання проекту, тобто в моєму файлі 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 , але це не допомогло.

Немає для цього елегантного рішення?


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 ++ являє собою досить негативну думку про -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та 1 його цільове призначення, але вони не відображаються в жодному з властивостей цього вихідного файлу.COMPILE_FLAGS

Ви можете подивитися, як зняти прапор проблеми з цілі 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властивість для цілей застаріле.


6
Але як ви насправді встановлюєте прапори компіляції для файлів окремо, не додаючи їх. Наприклад, я хочу використовувати різні прапори компіляції для отриманої цілі, ніж для файлів, але оскільки вони додаються, мені доведеться їх видалити вручну. Чи немає властивості, яка не додається, а фактично встановлює їх лише для вказаного файлу / цілі?
Бараде

2
Що робити, коли -fno-flag не доступний (і -fflag встановлено)?
gnzlbg

@ Baradé Ви не можете - не для вихідного файлу.
Фрейзер

@gnzlbg Знову ми майже застрягли. Я оновив свою відповідь, щоб дати трохи більше інформації (і можливого вирішення, яке, ймовірно, спрацювало б у деяких сценаріях).
Фрейзер

Чи дійсно немає вирішення налаштування параметрів компіляції одного файлу? Я маю вимкнути генерацію покриття gcc для деяких файлів, які виходять з ладу gcov.
Лотар

5

Просто додавання до правильної відповіді @ Фрейзера.

Якщо ви хочете додати спеціальний прапор до певних папок, ви можете:

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 (у мене включена тонна попереджень).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.