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


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.