我想删除单个翻译单元的set compile标志。有没有办法做到这一点? (例如,使用set_property
?)
注意:compile-flag没有-fno-name
否定(无论出于何种原因)。
我试过了:
get_property(FLAGS TARGET target PROPERTY COMPILE_FLAGS)
string(REPLACE "-fname" "" FLAGS ${FLAGS})
set_property(TARGET target PROPERTY COMPILE_FLAGS ${FLAGS})
没有任何运气。我要删除的属性是CMAKE_CXX_FLAGS
的一部分,因此不起作用。
答案 0 :(得分:15)
这个特定的解决方案(?)既适用于目标,也适用于单个翻译单元(单个.cpp
- 文件)。它需要CMake 3.7
或更新,因为我们需要使用BUILDSYSTEM_TARGETS
中添加的3.7
属性迭代所有现有目标。如果您无法使用3.7
或更新版本,则可以调整apply_global_cxx_flags_to_all_targets()
以获取目标列表并手动指定。请注意,您应该将下面的宏视为概念验证。他们可能需要对任何非常小的项目进行一些调整和改进。
第一步是遍历所有现有目标并将CMAKE_CXX_FLAGS
应用于每个目标。完成后,我们清除CMAKE_CXX_FLAGS
。您将在下面找到一个可以执行此操作的宏。这个宏应该在顶级CMakeLists.txt
的底部调用,当所有目标都已创建,所有标志都已设置等时。注意命令{{1}是很重要的。在目录级别工作,因此如果您使用get_property(_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
,则必须在该子目录的顶级add_subdirectory()
中调用此宏。
CMakeLists.txt
此宏首先从#
# Applies CMAKE_CXX_FLAGS to all targets in the current CMake directory.
# After this operation, CMAKE_CXX_FLAGS is cleared.
#
macro(apply_global_cxx_flags_to_all_targets)
separate_arguments(_global_cxx_flags_list UNIX_COMMAND ${CMAKE_CXX_FLAGS})
get_property(_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
foreach(_target ${_targets})
target_compile_options(${_target} PUBLIC ${_global_cxx_flags_list})
endforeach()
unset(CMAKE_CXX_FLAGS)
set(_flag_sync_required TRUE)
endmacro()
创建一个列表,然后获取所有目标的列表,并将CMAKE_CXX_FLAGS
应用于每个目标。最后,CMAKE_CXX_FLAGS
被清除。 CMAKE_CXX_FLAGS
用于表示我们是否需要强制重写缓存变量。
下一步取决于您是要从目标还是从特定翻译单元中删除标记。如果要从目标中删除标记,可以使用与此类似的宏:
_flag_sync_required
从特定翻译单元中删除标记有点棘手(除非我非常遗漏某些内容)。无论如何,我们的想法是首先从文件所属的目标获取编译选项,然后将所述选项应用于该目标中的所有源文件,这允许我们操作单个文件的编译标志。我们通过为每个要删除标志的文件维护一个缓存的编译标志列表来执行此操作,并且当请求删除时,我们将其从缓存列表中删除,然后重新应用其余标志。目标本身的编译选项已清除。
#
# Removes the specified compile flag from the specified target.
# _target - The target to remove the compile flag from
# _flag - The compile flag to remove
#
# Pre: apply_global_cxx_flags_to_all_targets() must be invoked.
#
macro(remove_flag_from_target _target _flag)
get_target_property(_target_cxx_flags ${_target} COMPILE_OPTIONS)
if(_target_cxx_flags)
list(REMOVE_ITEM _target_cxx_flags ${_flag})
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${_target_cxx_flags}")
endif()
endmacro()
我们有这个非常简单的项目结构:
#
# Removes the specified compiler flag from the specified file.
# _target - The target that _file belongs to
# _file - The file to remove the compiler flag from
# _flag - The compiler flag to remove.
#
# Pre: apply_global_cxx_flags_to_all_targets() must be invoked.
#
macro(remove_flag_from_file _target _file _flag)
get_target_property(_target_sources ${_target} SOURCES)
# Check if a sync is required, in which case we'll force a rewrite of the cache variables.
if(_flag_sync_required)
unset(_cached_${_target}_cxx_flags CACHE)
unset(_cached_${_target}_${_file}_cxx_flags CACHE)
endif()
get_target_property(_${_target}_cxx_flags ${_target} COMPILE_OPTIONS)
# On first entry, cache the target compile flags and apply them to each source file
# in the target.
if(NOT _cached_${_target}_cxx_flags)
# Obtain and cache the target compiler options, then clear them.
get_target_property(_target_cxx_flags ${_target} COMPILE_OPTIONS)
set(_cached_${_target}_cxx_flags "${_target_cxx_flags}" CACHE INTERNAL "")
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "")
# Apply the target compile flags to each source file.
foreach(_source_file ${_target_sources})
# Check for pre-existing flags set by set_source_files_properties().
get_source_file_property(_source_file_cxx_flags ${_source_file} COMPILE_FLAGS)
if(_source_file_cxx_flags)
separate_arguments(_source_file_cxx_flags UNIX_COMMAND ${_source_file_cxx_flags})
list(APPEND _source_file_cxx_flags "${_target_cxx_flags}")
else()
set(_source_file_cxx_flags "${_target_cxx_flags}")
endif()
# Apply the compile flags to the current source file.
string(REPLACE ";" " " _source_file_cxx_flags_string "${_source_file_cxx_flags}")
set_source_files_properties(${_source_file} PROPERTIES COMPILE_FLAGS "${_source_file_cxx_flags_string}")
endforeach()
endif()
list(FIND _target_sources ${_file} _file_found_at)
if(_file_found_at GREATER -1)
if(NOT _cached_${_target}_${_file}_cxx_flags)
# Cache the compile flags for the specified file.
# This is the list that we'll be removing flags from.
get_source_file_property(_source_file_cxx_flags ${_file} COMPILE_FLAGS)
separate_arguments(_source_file_cxx_flags UNIX_COMMAND ${_source_file_cxx_flags})
set(_cached_${_target}_${_file}_cxx_flags ${_source_file_cxx_flags} CACHE INTERNAL "")
endif()
# Remove the specified flag, then re-apply the rest.
list(REMOVE_ITEM _cached_${_target}_${_file}_cxx_flags ${_flag})
string(REPLACE ";" " " _cached_${_target}_${_file}_cxx_flags_string "${_cached_${_target}_${_file}_cxx_flags}")
set_source_files_properties(${_file} PROPERTIES COMPILE_FLAGS "${_cached_${_target}_${_file}_cxx_flags_string}")
endif()
endmacro()
我们假设source/
CMakeLists.txt
foo.cpp
bar.cpp
main.cpp
违反了foo.cpp
,我们希望在该特定文件上禁用该标志。对于-Wunused-variable
,我们要禁用bar.cpp
。对于-Werror
,我们想要删除main.cpp
,无论出于何种原因。
<强>的CMakeLists.txt 强>
-O2
如果您想要从目标中移除标记,则可以使用cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
project(MyProject)
# Macros omitted to save space.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wunused-variable")
# CMake will apply this to all targets, so this will work too.
add_compile_options("-Werror")
add_executable(MyTarget foo.cpp bar.cpp main.cpp)
apply_global_cxx_flags_to_all_targets()
remove_flag_from_file(MyTarget foo.cpp -Wunused-variable)
remove_flag_from_file(MyTarget bar.cpp -Werror)
remove_flag_from_file(MyTarget main.cpp -O2)
,例如:remove_flag_from_target()
应用宏之前的输出
remove_flag_from_target(MyTarget -O2)
应用宏后的输出
clang++ -Werror -O2 -Wunused-variable -o foo.cpp.o -c foo.cpp
clang++ -Werror -O2 -Wunused-variable -o bar.cpp.o -c bar.cpp
clang++ -Werror -O2 -Wunused-variable -o main.cpp.o -c main.cpp
如上所述,这应被视为概念验证。有一些需要立即考虑的问题:
clang++ -Werror -O2 -o foo.cpp.o -c foo.cpp
clang++ -O2 -Wunused-variable -o bar.cpp.o -c bar.cpp
clang++ -Werror -Wunused-variable -o main.cpp.o -c main.cpp
(所有构建类型都通用),而不是CMAKE_CXX_FLAGS
等。CMAKE_CXX_FLAGS_<DEBUG|RELEASE>
一次只能处理一个目标和输入文件作为输入。remove_flag_from_file()
需要文件名,而不是路径。传递,比方说remove_flag_from_file()
将不起作用,因为source/foobar/foobar.cpp
将与source/foobar/foobar.cpp
进行比较。可以使用foobar.cpp
和get_source_file_property()
属性修复此问题,并设置LOCATION
为完整路径的前提条件。
_file
可能会得到很好的优化和改进。remove_flag_from_file()
的调用假设为Unix。其中大部分都应该很容易解决。
我希望这至少能帮助你解决这个问题。如果我需要在答案中添加一些东西,请告诉我。
答案 1 :(得分:8)
如果没有编译标志否定选项(这将是CMake处理非IDE配置器的标准方法),则必须从CMAKE_CXX_FLAGS
中删除此编译标志。
使COMPILE_FLAGS
源文件属性INHERITED
来自具有相同名称的目录属性。现在,您可以单独修改每个目录和源文件的COMPILE_FLAGS
属性:
# Remove '-fname' from global flags
string(REPLACE "-fname" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
define_property(
SOURCE
PROPERTY COMPILE_FLAGS
INHERITED
BRIEF_DOCS "brief-doc"
FULL_DOCS "full-doc"
)
# Add '-fname' for directory
set_directory_properties(PROPERTIES COMPILE_FLAGS "-fname")
add_executable(${PROJECT_NAME} "main.cpp")
# Remove '-fname' from source file
set_source_files_properties("main.cpp" PROPERTIES COMPILE_FLAGS "")
如果某些属性(如COMPILE_OPTIONS
)仅在目标级别上可用,则必须将要进行不同设置的文件移动到单独的新目标中。
可以使用OBJECT libraries:
来完成# Remove '-fname' from global flags
string(REPLACE "-fname" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
# Set '-fname' for directory, but if you also use add_compile_options() be aware that
# this will overwrite your previous setting. Append/remove properties instead.
set_directory_properties(
PROPERTIES
COMPILE_OPTIONS "-fname"
)
# Remove '-fname' from source file(s) in separate object library target
add_library(${PROJECT_NAME}_no_name OBJECT "main.cpp")
set_target_properties(
${PROJECT_NAME}_no_name
PROPERTIES
COMPILE_OPTIONS ""
)
# Use object library target in e.g. executable target
add_executable(${PROJECT_NAME} $<TARGET_OBJECTS:${PROJECT_NAME}_no_name>)
答案 2 :(得分:4)
(不可扩展和非可移植)解决方案是使用修改后的标志创建自定义命令。我工作的一个最小例子是:
cmake_minimum_required(VERSION 2.8)
project(test)
# Some flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall")
# Remove unwanted flag
string(REPLACE "-Wall" "" CUSTOM_FLAGS ${CMAKE_CXX_FLAGS})
# Split the flags into a cmake list (; separated)
separate_arguments(CUSTOM_FLAGS UNIX_COMMAND ${CUSTOM_FLAGS})
# Custom command to build your one file.
add_custom_command(
OUTPUT out.o
COMMAND ${CMAKE_CXX_COMPILER}
ARGS ${CUSTOM_FLAGS} -c ${CMAKE_SOURCE_DIR}/out.cpp
-o ${CMAKE_BINARY_DIR}/out.o
MAIN_DEPENDENCY out.cpp)
add_executable(test test.cpp out.o)
虽然远非完美,但它确实起作用。 separate_arguments
是必要的,因为否则CUSTOM_FLAGS
中的所有空格都被转义(不知道如何快速解决)。