How to create an artificial circular dependency between targets - visual-studio

I have an executable (game engine) which exports symbols (I've used set_target_properties(game PROPERTIES ENABLE_EXPORTS ON)).
I have a bunch of plugins that link to that executable:
foreach(plugin ${PLUGINS})
target_link_libraries(${plugin} game)
endforeach()
They are loaded dynamically with LoadLibrary/dlopen by the executable.
When I press F5 in Visual Studio and I start the game I don't get the changed plugins rebuilt because the game does not depend on them - it's the other way around.
I wanted to do the following:
foreach(plugin ${PLUGINS})
add_dependencies(game ${plugin})
endforeach()
but it introduces a circular dependency between each plugin and the game. How can I solve my F5 problem?

That's a "chicken-and-egg" problem since the game build will generate the import libraries needed by plugin. So you can't build plugin before game.
I've given your scenario a try and
If I force a rebuild in a POST_BUILD step, I get obviously a recursive build call:
add_custom_command(
TARGET game
POST_BUILD
COMMAND ${CMAKE_COMMAND} --build . --target ALL_BUILD --config $<CONFIG>
)
If I construct a separate target as a "runner" target, I would probably confusing others using my project:
file(WRITE nobuild.cpp "")
add_executable(game_runner nobuild.cpp)
set_source_files_properties(nobuild.cpp PROPERTIES HEADER_FILE_ONLY 1)
set_target_properties(game_runner PROPERTIES OUTPUT_NAME "game")
foreach(plugin ${PLUGINS})
add_dependencies(game_runner ${plugin})
endforeach()
So probably your suggestion of re-using the ALL_BUILD target is the best one. And for auto-generating your required .user settings you may find the following interesting:
CMake add_custom_target(): Run custom command using 'Debug->Start Debugging'
I've used the following to test your scenario:
project(TestPlugins)
file(WRITE main.cpp "int main() { return 0; }")
file(WRITE empty.cpp "")
add_executable(game main.cpp)
set_target_properties(game PROPERTIES ENABLE_EXPORTS ON)
set_target_properties(game PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_executable(plugin1 empty.cpp)
add_executable(plugin2 empty.cpp)
set(PLUGINS plugin1 plugin2)
foreach(plugin ${PLUGINS})
target_link_libraries(${plugin} game)
endforeach()

Related

How do you pass Menuconfig variables to your cmake file ( in ESP-IDF )

I am trying to configure to my build process for ESP-IDF to slim down the build. What I have tried : I've added custom entries to the menuconfig:
menu "Install Sensor Device Drivers"
config LISD3H_CHECK
bool "Include LISD3H Accel Sensor"
default "n"
help
Install required drivers for LISD3H and check if device present
config SHT30_CHECK
bool "Include SHT30 Temp & Hum Sensor"
default "n"
help
Install required drivers for SHT30 and check if device present
endmenu
and tried using these to reduce unnecessary components getting compiled into the project. The config variables are correctly created and accessible within the source code. Now, I tried to control the build within the top level cmake file:
set(component_dirs "${CMAKE_CURRENT_LIST_DIR}/../components/comp1")
message(STATUS ${component_dirs})
message(STATUS ${CONFIG_LISD3H_CHECK})
message(STATUS ${CONFIG_SHT30_CHECK})
if(CONFIG_LISD3H_CHECK)
list(APPEND component_dirs "${CMAKE_CURRENT_LIST_DIR}/../components/comp2" )
message(STATUS ${component_dirs})
else()
message(STATUS "config not equal to whategver...")
endif()
However, the if statement is always false because cmake cannot see the CONFIG_XXXX variables from Kconfig (the messages are blank) Is there a way to access Kconfig varaibles inside cmake? Or a means of using menuconfig to control the build?
Basically, How do you exclude a component from the build? Should I just use C precompile directives inside the source code and ignore what gets compiled, since it will get optimised out of the final binary?
You should be on the correct path according to the ESP IDF build system documentation. Did you add your options to Kconfig in the main component? Note that you need to actually run idf.py menuconfig and choose your configuration before it becomes visible to cmake, after which the root sdkconfig file should have them set.
For example, in the ESP IDF project's main/Kconfig.projbuild file I added
menu "Test Configuration"
config TESTOPTION_YAY
bool "Enable test option"
endmenu
Then in the project root CMakeLists.txt I added:
message(STATUS CONFIG_TESTOPTION_YAY: ${CONFIG_TESTOPTION_YAY})
Now I run idf.py menuconfig and set the test option on or off. Subsequently I build with idf.py build - the build log shows -- CONFIG_TESTOPTION_YAY:y or -- CONFIG_TESTOPTION_YAY: depending on the choice I made.

Visual Studio Solution Style using CMakelists [duplicate]

I have a CMake project that looks like this:
project/
CMakeLists.txt
subprojectA/
CMakeLists.txt
include/
headerA.hpp
src/
libraryA.cpp
subprojectB/
CMakeLists.txt
src/
mainB.cpp
The "library" subproject, A, is compiled as a static library, becoming libsubprojectA.a. The "main" project, B, is compiled as a binary and depends on the library. mainB.cpp includes a reference to headerA.hpp.
Here is subprojectA/CMakeLists.txt:
project(SubProjectA)
include_directories(include)
add_library(subprojectA STATIC src/libraryA.cpp)
set(${PROJECT_NAME}_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/include
CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
And here is subprojectB/CMakeLists.txt:
project(SubProjectB)
include_directories(${SubProjectA_INCLUDE_DIRS})
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
The main Project CMakeLists.txt looks like:
project(Project)
add_subdirectory(subprojectB)
add_subdirectory(subprojectA)
Note that subprojectB, the main project, is listed before subprojectA.
Here's the problem. When I first run "cmake" on this project, ${SubProjectA_INCLUDE_DIRS} is not set within SubProjectB.
What I think is happening is that the CMakeLists for SubProjectB loads first, when ${SubProjectA_INCLUDE_DIRS} has not yet been set. It sets its own include path to an empty string as a result. However, even though libsubprojectA.a gets built successfully before mainBinary, the include path was already set empty beforehand. As a result, I get this error when trying to make mainBinary:
subprojectB/src/mainB.cpp:1:23: fatal error: headerA.hpp: No such file or directory
#include "headerA.hpp"
^
It's a workaround to put subprojectA before subprojectB in the main Project CMakeLists in the declarative world of CMake. What I really want is to know the proper way to indicate to CMake that the include_directories(${SubProjectA_INCLUDE_DIRS}) line depends on the definitions that exist inside SubProjectA's CMakeLists. Is there a better way to do this?
If you want to express that include directory subprojectA/include is an interface of the library subprojectA, attach this property to the target with target_include_directories command:
subprojectA/CMakeLists.txt:
project(SubProjectA)
add_library(subprojectA STATIC src/libraryA.cpp)
# PUBLIC adds both:
# 1) include directories for compile library and
# 2) include directories for library's interface
target_include_directories(subprojectA PUBLIC include)
So any executable(or other library) which linked with subprojectA will have this include directory automatically:
subprojectB/CMakeLists.txt:
project(SubProjectB)
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
Of course, for use last command properly you need to process directory with library before one with executable:
CMakeLists.txt:
project(Project)
add_subdirectory(subprojectA)
add_subdirectory(subprojectB)

cmake: add_custom_command only invoked first time

I'm running into a problem with add_custom_command for a custom target (created using add_custom_target).
My general idea is to incorporate a static code analysis tool into the cmake tool-chain. My solution is based on the one described here: https://github.com/rpavlik/cmake-modules/blob/master/CppcheckTargets.cmake
In a nutshell, each project that I want to run static code analysis for has the following two lines of code:
include(cppcheck)
add_cppcheck(${le_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
The module has this at the top of the file:
if (NOT TARGET ANALYZE_CODE)
add_custom_target(ANALYZE_CODE WORKING_DIRECTORY ${LE_LITEN_ROOT})
set_target_properties(ANALYZE_CODE PROPERTIES EXCLUDE_FROM_ALL TRUE)
endif ()
and later on in the function the custom command is added:
add_custom_command(TARGET
ANALYZE_CODE
PRE_BUILD
COMMAND
${CPPCHECK_EXECUTABLE}
${CPPCHECK_QUIET_ARG}
${CPPCHECK_TEMPLATE_ARG}
${_cppcheck_args}
${_files}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT
"${_name}_cppcheck: Running cppcheck on target ${_name}..."
VERBATIM)
The problem I'm seeing is that the command is only added for the project that included the file first. I'm not sure why and what is going on. I verified the following using message() commands:
The target is only created once
The add_custom_command is run for every project that calls the function, with proper arguments
But when I actually look at the target in visual studio, only the first include / function call command is added.
If the file is only included without calling the function, no custom commands are added at all.
Desired behavior:
I would like ONE target named "ANALYZE_CODE" to run all commands added by calls to the function.
I.e. if 3 projects include the two lines from above, the target ANALYZE_CODE is created once but 3 custom commands are added to it, one for each project.
It turns out you're somewhat stuck between a rock and a hard place here. The issue I think boils down to a couple of factors.
Firstly, although the docs don't make it clear, add_custom_command(TARGET ...) only works for targets created in the same directory. So the first subproject to call include(cppcheck) is the only one which can effectively add custom commands to the target ANALYZE_CODE.
A workaround for this might seem to be to move all calls to add_cppcheck from their respective subdirectories up to the top-level CMakeLists file.
include(cppcheck)
add_cppcheck(${le_first_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
add_cppcheck(${le_second_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
...
This isn't a great solution, since these really belong inside their own subdirs. But a bigger issue is that properties on source files only persist in the scope of the CMakeLists.txt in which they are added. This isn't obvious at all, but from the docs for set_source_files_properties:
Source file properties are visible only to targets added in the same directory (CMakeLists.txt).
The innards of the add_cppcheck have the following block of code:
foreach(_source ${_cppcheck_sources})
get_source_file_property(_cppcheck_lang "${_source}" LANGUAGE)
get_source_file_property(_cppcheck_loc "${_source}" LOCATION)
if("${_cppcheck_lang}" MATCHES "CXX")
list(APPEND _files "${_cppcheck_loc}")
endif()
endforeach()
So this is checking that each source file for the given target is designated as a C++ file before adding it to the list of files to be given to cppcheck. If this function is invoked from within the CMakeLists.txt where the target is defined (i.e. the subdir) then the files all have the appropriate property and are correctly added.
However, if the function is called from the parent CMakeLists.txt, the files have lost their properties, and so none are added and cppcheck is passed an empty list!
Now for the possible fixes. There are probably few ways to get out of this hole - I can point to a couple.
You could continue with the option to always call add_cppcheck from the top-level CMake file and avoid using the source files' properties. So the problem codeblock above could be changed to something more like:
set(CxxExtensions .cpp .CPP .cc .CC .cxx .CXX)
foreach(_source ${_cppcheck_sources})
get_filename_component(Extension "${_source}" EXT)
list(FIND CxxExtensions "${Extension}" IsCxxFile)
if(IsCxxFile GREATER -1)
list(APPEND _files "${_source}")
endif()
endforeach()
You could even enforce that the function is only called from the top-level CMakeLists.txt by adding something like this at the start of the function:
if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
message(FATAL_ERROR "This can only be called from the top-level CMakeLists.txt")
endif()
The second fix (which I'd personally favour) is to leave the add_cppcheck calls inside the subdirs and have the function add a custom target rather than command. These targets can successfully be applied as dependencies of the top-level target ANALYZE_CODE. So for example, change the add_custom_command to something like:
add_custom_target(ANALYZE_${_name}
${CPPCHECK_EXECUTABLE}
${CPPCHECK_QUIET_ARG}
${CPPCHECK_TEMPLATE_ARG}
${_cppcheck_args}
${_files}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "ANALYZE_${_name}: Running cppcheck on target ${_name}..."
VERBATIM)
add_dependencies(ANALYZE_CODE ANALYZE_${_name})
set_target_properties(ANALYZE_${_name} PROPERTIES FOLDER "Code Analysis")
This should cause building ANALYZE_CODE to trigger building each of the subordinate ANALYZE_... targets.
It has the downside of "polluting" the solution with a lot of extra targets, but an upside is that you could use these targets in the add_test calls (although this may be a step too far):
# CMake 2.8.0 and newer
add_test(NAME ${_name}_cppcheck_test
COMMAND ${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}
--target ANALYZE_${_name})

Copy target file to another location in a post build step in CMake

I have a dynamic library that gets a different name depending on configuration, specified in the CMake scripts by:
set_target_properties(${name} PROPERTIES OUTPUT_NAME ${outputName}64)
set_target_properties(${name} PROPERTIES DEBUG_OUTPUT_NAME ${outputName}64_d)
The end result is that I get a different name on release and debug builds. I would like to copy the resulting library to a different directory as a post-build step, but the gift(?) of CMake-Fu did not smile upon yours truly.
I have tried doing this:
GET_TARGET_PROPERTY(origfile mylibrary LOCATION)
STRING(REGEX REPLACE "/" "\\\\" origfile ${origfile})
set(targetfile my_target_path\\${CMAKE_CFG_INTDIR}\\)
STRING(REGEX REPLACE "/" "\\\\" targetfile ${targetfile})
add_custom_command(TARGET mylibrary POST_BUILD
COMMAND copy ${origfile} ${targetfile}
)
This works fine for release builds, but for debug the source does not include the _d that I would have expected.
How do I get the output path for the target so that I can copy the file?
Note: As can be seen from the above snippet, this is currently for Windows/Visual Studio, but I would like this to work on OS X / Xcode / make as well.
Note: I need the library to be placed in an extra directory that serves as the output directory for several other projects that depend on this library, so that these projects are able to load the library at runtime. An alternative solution that would be acceptable would be to be able to create a custom target that does the copying, so that the other projects can depend on this project, which in turn depends on the library.
Rather than using the obsolete LOCATION property, prefer using generator expressions:
add_custom_command(TARGET mylibrary POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:mylibrary> ${targetfile}
)
You could also just generate the exe in the target directory directly by setting the target property RUNTIME_OUTPUT_DIRECTORY instead of copying it. This has per-configuration options (e.g. RUNTIME_OUTPUT_DIRECTORY_DEBUG).
set_target_properties(mylibrary PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_DEBUG <debug path>
RUNTIME_OUTPUT_DIRECTORY_RELEASE <release path>
)
For further details run:
cmake --help-property "RUNTIME_OUTPUT_DIRECTORY"
cmake --help-property "RUNTIME_OUTPUT_DIRECTORY_<CONFIG>"
Also, you should be able to use forward slashes throughout for path separators, even on Windows.
Use generator expressions in the POST_BUILD command instead of manually computing the output path. These are configuration aware. Example:
add_custom_command(TARGET mylibrary POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:mylibrary>"
"my_target_path/$<CONFIGURATION>/$<TARGET_FILE_NAME:mylibrary>"
COMMENT "Copying to output directory")
The other answers weren't 100% clear to me...
Say you're building an executable test_base.exe, the following will build the executable then copy the .exe to the base 'build' directory:
add_executable(test_base "")
target_sources(test_base
PRIVATE
catch_main.cpp
catch_tests.cpp
sc_main.cpp
)
target_link_libraries(test_base PRIVATE Catch2 systemc)
add_custom_command(TARGET test_base POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:test_base> ${PROJECT_BINARY_DIR}/test_base.exe
COMMENT "Created ${PROJECT_BINARY_DIR}/test_base.exe"
)
So, after this runs your project will have:
<project dir>/build/test_base.exe

using xib in firebreath plugin

I've created a firebreath plugin on mac os which HAVE TO pop up a window to get user input(just a text field and two buttons).
This is my current projectDef.cmake for testing.
file (GLOB XIB RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
Mac/bundle_template/input.xib
)
# Make sure we can find the 'ibtool' program. If we can NOT find it we
# skip generation of this project
find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
if (${IBTOOL} STREQUAL "IBTOOL-NOTFOUND")
message(SEND_ERROR "ibtool can not be found and is needed to compile the .xib files. It should have been installed with the Apple developer tools. The default system paths were searched in addition to ${OSX_DEVELOPER_ROOT}/usr/bin")
endif()
# make the compiled nib file to desktop for testing
set (NIBFILE /Users/develop/Desktop/input.nib)
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text --compile ${NIBFILE} ${XIB}
COMMENT "Compiling input.xib")
set (SOURCES
${SOURCES}
${PLATFORM}
${XIB}
)
the add_custom_command block takes no effect from cmake, no nib file compiled when my plugin target build successfully, but ibtool works from command line in terminal.
Looks like what you need to do is compile the .xib file to a .nib file. There is an example of how to do that here:
http://www.cmake.org/Wiki/CMake:OSX_InterfaceBuilderFiles
basically you'll do something similar to this:
# Make sure we can find the 'ibtool' program. If we can NOT find it we
# skip generation of this project
find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
if (${IBTOOL} STREQUAL "IBTOOL-NOTFOUND")
message(SEND_ERROR "ibtool can not be found and is needed to compile the .xib files. It should have been installed with the Apple developer tools. The default system paths were searched in addition to ${OSX_DEVELOPER_ROOT}/usr/bin")
endif()
set (NIBFILE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/input.nib)
add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text
--compile ${NIBFILE} ${XIB}
COMMENT "Compiling input.xib")
set (SOURCES
${SOURCES}
${PLATFORM}
${XIB}
${NIBFILE}
)
set_source_files_properties(${NIBFILE}
PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources/English.lproj"
GENERATED 1
)
You need to set the location for the NIB file, but remember that you also need to set it to GENERATED because it won't be there when the prep script is run for the first time.
Problem solved. See this link. That method works. My final solution is as follows:
//projectDef.cmake
set(XIB "Mac/bundle_template/input.xib")
add_mac_plugin(${PROJECT_NAME} ${PLIST} ${STRINGS} ${LOCALIZED} SOURCES ${XIB})
//Mac.cmake in "add_mac_plugin" macro
if (${ARGC} GREATER 5)
add_library( ${PROJECT_NAME} MODULE
${SOURCES}
${ARGN}
)
else()
add_library( ${PROJECT_NAME} MODULE
${SOURCES}
)
endif()
if (${ARGC} GREATER 5)
set_target_properties(${PROJECT_NAME} PROPERTIES
BUNDLE 1
BUNDLE_EXTENSION plugin
XCODE_ATTRIBUTE_WRAPPER_EXTENSION plugin #sets the extension to .plugin
XCODE_ATTRIBUTE_MACH_O_TYPE mh_bundle
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
RESOURCE ${ARGN}
LINK_FLAGS "-Wl,- exported_symbols_list,${FB_ESC_ROOT_DIR}/gen_templates/ExportList_plugin.txt")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES
BUNDLE 1
BUNDLE_EXTENSION plugin
XCODE_ATTRIBUTE_WRAPPER_EXTENSION plugin #sets the extension to .plugin
XCODE_ATTRIBUTE_MACH_O_TYPE mh_bundle
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist
LINK_FLAGS "-Wl,-exported_symbols_list,${FB_ESC_ROOT_DIR}/gen_templates/ExportList_plugin.txt")
endif()
My modification seems not so beautiful, I don't understand cmake very well. hi taxilian, can you update the macro to support external resources like xib? By the way, thanks a lot, man.

Resources