I have big project. In root directory I've created file CMake\optionalsource.cmake
(in directory CMake
are other helper files), which contains this function definitions:
cmake_minimum_required(VERSION 3.5)
# cmake_parse_arguments needs cmake 3.5
##
# This function always adds sources to target, but when "WHEN" condition is not meet
# source is excluded from build process.
# This doesn't break build, but source is always visible for the project, what is
# very handy when working with muti-platform project with sources needed
# only for specific platform
#
# Usage:
# target_optional_sources(WHEN <condition>
# TARGET <target>
# <INTERFACE|PUBLIC|PRIVATE> [items2...]
# [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
##
function(target_optional_sources)
set(options OPTIONAL "")
set(oneValueArgs WHEN TARGET)
set(multiValueArgs PUBLIC PRIVATE INTERFACE)
cmake_parse_arguments(target_optional_sources
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN})
# for debugging purposes
message("TARGET ${target_optional_sources_TARGET}")
message("PUBLIC ${target_optional_sources_PUBLIC}")
message("PRIVATE ${target_optional_sources_PRIVATE}")
message("INTERFACE ${target_optional_sources_INTERFACE}")
message("WHEN ${target_optional_sources_WHEN} ${${target_optional_sources_WHEN}}")
target_sources(${target_optional_sources_TARGET}
PUBLIC ${target_optional_sources_PUBLIC}
PRIVATE ${target_optional_sources_PRIVATE}
INTERFACE ${target_optional_sources_INTERFACE})
if (NOT ${target_optional_sources_WHEN})
set_source_files_properties(${target_optional_sources_PUBLIC}
PROPERTIES HEADER_FILE_ONLY TRUE)
set_source_files_properties(${target_optional_sources_PRIVATE}
PROPERTIES HEADER_FILE_ONLY TRUE)
set_source_files_properties(${target_optional_sources_INTERFACE}
PROPERTIES HEADER_FILE_ONLY TRUE)
endif(NOT ${target_optional_sources_WHEN})
endfunction(target_optional_sources)
This is included into a root CMakeLists.txt
.
Now this function quite simple. It was motivated by this nice SO answer and this feature request for CMake.
Now I've encounter some strange problem. My project contains many targets (libs/dlls/execs), I used this function in one place like this:
add_library(CommonLibrary STATIC
<list of mutliplatform sources>
)
message("=== function CommonLibrary ===")
target_optional_sources(WHEN APPLE
TARGET CommonLibrary
PUBLIC
macos/CFUtils.cpp
macos/CFUtils.h
MacMachineData.mm
MacMachineData.h
macos/MacAutoreleasePool.mm
macos/MacAutoreleasePool.h
)
And in logs I can see this:
1>=== function CommonLibrary ===
1>TARGET CommonLibrary
1>PUBLIC macos/CFUtils.cpp;macos/CFUtils.h;MacMachineData.mm;MacMachineData.h;macos/MacAutoreleasePool.mm;macos/MacAutoreleasePool.h
1>PRIVATE
1>INTERFACE
1>WHEN APPLE
But lower I can see this error messages:
1>CMake Error at SomeOtherLib1/CMakeLists.txt:34 (add_executable):
1> Cannot find source file:
1>
1> macos/CFUtils.cpp
1>
1> Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
1> .hpp .hxx .in .txx
1>
1>
1>CMake Error at SomeOtherLib2/CMakeLists.txt:11 (add_executable):
1> Cannot find source file:
1>
1> macos/CFUtils.cpp
1>
1> Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
1> .hpp .hxx .in .txx
1>
1>
1>CMake Error at UnitTests/CMakeLists.txt:11 (add_executable):
1> Cannot find source file:
1>
1> macos/CFUtils.cpp
1>
1> Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
1> .hpp .hxx .in .txx
1>
macos/CFUtils.cpp
was added only by invoking my custom function, so how it is possible that other CMakeLists.txt
files has been impacted by successful function invocation? When I reorder files in function invocation error messages are following this change.
What is more strange under Visual Studio this errors are coursing error report, but project files are regenerated successfully and everything works. I can't live this as it is since it will cause build issue on Jenkins machine.
Edit:
This is how CommonLibrary
is linked to other targets, for example:
add_executable(TestApp
<Test app sources>
)
target_link_libraries(TestApp
PRIVATE
fmt::fmt-header-only
CommonLibrary
SomeOtherLibrary
)