I would like to change CMAKE_C_COMPILER and CMAKE_CXX_COMPILER in an inner sub_directory being compiled as part of a bigger project.
changing from GNU to intel compiler. however, outside of this directory nothing has to chagne.
is that possible?
Thanks
Instead of using add_subdirectory consider making the subdirectory a self-contained CMake project, which can be configured and built independently of the bigger project. You can then add the subdirectory to your bigger project as an external project by using the ExternalProject_Add command.
It depends, how you organize your project.
If it is not single CMakeLists.txt for whole project, but one per each sub folder - just try to change CMAKE_C_COMPILER before project() definition.
It should affect only this project definition.
Related
I would like to change CMAKE_C_COMPILER and CMAKE_CXX_COMPILER in an inner sub_directory being compiled as part of a bigger project.
changing from GNU to intel compiler. however, outside of this directory nothing has to chagne.
is that possible?
Thanks
Instead of using add_subdirectory consider making the subdirectory a self-contained CMake project, which can be configured and built independently of the bigger project. You can then add the subdirectory to your bigger project as an external project by using the ExternalProject_Add command.
It depends, how you organize your project.
If it is not single CMakeLists.txt for whole project, but one per each sub folder - just try to change CMAKE_C_COMPILER before project() definition.
It should affect only this project definition.
I'm grouping sources in folders by some rules and I want to be able to individually test each group in isolation for faster iteration. To do so I want to CMake to generate one executable for each group. I simplified the project structure to:
root
build
group_1
CMakeLists.txt
group_1_file_1.cpp
group_1_tests
CMakeLists.txt
group_1_file_1_tests.cpp
where group_1/CMakeLists.txt is:
SET(group_1_srcs
${CMAKE_CURRENT_SOURCE_DIR}/group_1_file_1.cpp
)
#Generate standalone application for unit tests when cmake is started with this CMakeLists as root
IF(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
ADD_SUBDIRECTORY("group_1_tests/")
ENDIF()
and group_1/group_1_tests/CMakeLists.txt is
PROJECT(group_1_tests)
SET(group_1_tests_srcs
${CMAKE_CURRENT_SOURCE_DIR}/group_1_file_1_tests.cpp
)
ADD_EXECUTABLE(${PROJECT_NAME} "${group_1_tests_srcs}" "${group_1_srcs}")
Running cmake ../group_1 from root/build/ generates me the project I want, root/build/group_1_tests/group_1_tests.sln, but also root/build/Project.sln with the same files & settings as the previous one.
Can you please explain why this projects gets generate and how may I avoid it?
The answer is in the project() command documentation:
The top-level CMakeLists.txt file for a project must contain a literal, direct call to the project() command ... If no such call exists CMake will implicitly add one to the top that enables the default languages (C and CXX).
So Project is the default project's name. And from that point onward CMake generates a .sln solution for all CMakeLists.txt containing another project() command.
I would recommend you ignore the root solution file (if you don't want it) or restructure your project to have a single project() command call in the root CMakeList.txt (since your sub-level project won't run standalone without the top-level project anyway).
References
CMake Commit: ENH: generate a sln and dsw file for each sub project in a project
I have a scenario that I think is very similar to this one: CMake add_custom_command/_target in different directories for cross-compilation, however the solution for that issue isn't working for me.
In subdir/CMakeLists.txt I have:
add_custom_command(OUTPUT foo.h foo.cpp COMMAND ... DEPENDS foo.xml)
add_custom_target(generate_foo DEPENDS foo.h foo.cpp)
and then CMakeLists.txt:
add_executable(MyTarget
subdir/foo.h
subdir/foo.cpp
${OTHER_SOURCES})
add_dependencies(MyTarget generate_foo)
add_subdirectory(subdir)
This fails with "Cannot find source file: subdir/foo.h". The documentation for add_dependencies suggests that it will ensure that generate_foo builds before MyTarget, but if that's the case it looks like it's at least trying to access all source files before either target builds. Am I doing something wrong here? How can I compile source files that are generated by a custom target/command in a subdirectory?
The problem is that the GENERATED file property (that CMake uses to determine if it needs to check that a file exists at configure time) is not visible outside the directory in which the file is generated. The problem goes away in CMake 3.20. This is explained here.
I usually solve this problem by compiling generated source files into a static or object library in the subdirectory, then linking to that, since targets are globally visible. You can also explicitly set the GENERATED property on the generated files in the scope you wish to use them, but this hack breaks the encapsulation gained by using a subdirectory.
It's also worth noting that you can do away with the custom target and the call to add_dependencies because the generated files are already dependencies of the executable (this has always has been the case AFAIK).
I have a huge project managed with CMake and this project has hundreds of components each of them having own source files and each of them linking to a list of libraries, specified with target_link_libraries(${project} some_libraries, some_other_libraries)
Now, what I am aiming for is that:
Without actually modifying any of the CMakeLists.txt I want ALL the projects's target executable to link to some specific libraries.
Is there a way of achieving this? Since this is a one time trial, I don't want to manually hunt down all the CMakeLists.txt files and modify them (yes, this is the other alternative). Just a note, I compile the entire project from command line, using cmake (no cmake gui).
This is kind of a hack, but for a C++ project, you can use CMAKE_CXX_STANDARD_LIBRARIES. For a C project, I think you would use CMAKE_C_STANDARD_LIRBARIES.
Example for C++ that links to libbar and libfoo:
cmake ... -DCMAKE_CXX_STANDARD_LIBRARIES="-lbar -lfoo"
See the documentation here:
https://cmake.org/cmake/help/v3.6/variable/CMAKE_LANG_STANDARD_LIBRARIES.html
This won't be available for older versions of CMake; it was added some time after version 3.0.
This is a dirty, dirty hack, so please only use it for testing.
You can actually overload the add_executable command by defining a function of the same name. Do this close to the top of the top-level CMakeLists.txt:
function (add_executable name)
message("Added executable: " ${name})
_add_executable(${name} ${ARGN})
target_link_libraries(${name$} your_additional_lib)
endfunction()
Note that _add_executable is an internal CMake name that may break in future CMake versions. As of now (version 3.0) it seems to work with all versions though.
You can overload add_library the same way if required.
For more fine-grained control over what is linked, instead of calling target_link_libraries you can also mess with the LINK_LIBRARIES and INTERFACE_LINK_LIBRARIES target properties directly.
I have the following directory layout:
main_folder
+ static_lib1
+ executable
Both 'static_lib1' and 'executable' have a full CMakeLists so that they can be
built independently.
The 'executable' depends on 'static_lib1'. It uses find_package() to locate 'static_lib1'.
The main_folder contains a CMakeLists that includes both 'static_lib1' and 'executable' via add_subdirectory for conveniently building the whole project in one go.
Everything works fine if I manually build 'static_lib1' and then 'executable'. But when running the CMakeLists from the main folder, I get an error because find_package is unable to find the library files from 'static_lib1' which have not yet been built.
How can I resolve this while keeping the CMakeLists files separate (i.e. without including the static_lib's CMakeLists from the executable's CMakeLists)?
In executable's CMakeLists.txt you can check if you are building stand-alone or as part of project:
if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
# stand-alone build
find_package(static_lib1)
else()
include_directories(../static_lib1)
link_directories(../static_lib1)
...
target_link_libraries(executable static_lib1)
endif()
Switch from a file-based approach to a target-based approach for handling the dependency from executable to static_lib1.
The original problem occurred because executable called find_package for locating static_lib1, which then attempted to fill a variable like STATIC_LIB1_LIBRARY with the paths to the library files by calling find_library. executable then consumes the content of that variable in a target_link_libraries(executable ${STATIC_LIB1_LIBRARY}) call. The problem here is, since those library files only get generated as part of the build, that call to find_library will not be able to find anything.
Building executable needs to support two scenarios here:
Building standalone, where a pre-compiled version of static_lib1 is located somewhere on the disc.
Building from main_folder, where both executable and static_lib1 are part of the same build.
The approach from the question supports scenario 1, but not scenario 2.
Instead of using using a variable to communicate a dependency between the two builds, use a target. The CMakeLists.txt for static_lib1 likely creates a library target like add_library(static_lib1 [...]). In executable we now simply do target_link_libraries(executable PUBLIC static_lib1). This is sufficient to support scenario 2.
To also allow for scenario 1 at the same time, we look at the call to find_package(static_lib1) in the CMakeLists.txt for executable. Instead of providing a variable like before, this call now needs to provide a target static_lib1 for consumption.
So we adapt the find script for static_lib1 to the following behavior:
If a target static_lib1 already exists, there's nothing to be done and the find script can just return (this is scenario 2).
Otherwise, we call find_library to locate the library file on disc (as before in the original approach) and then create a new imported target: add_library(static_lib1 STATIC IMPORTED). We then configure all relevant properties of the static library to that target. For instance, to add the location of the library file, we could do
set_target_properties(static_lib1 PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION ${STATIC_LIB1_LIBRARY}
)
To support multi-config generators like MSVC, instead of setting IMPORTED_LOCATION and IMPORTED_LINK_INTERFACE_LANGUAGES, you will want to set the configuration specific properties like IMPORTED_LOCATION_DEBUG and IMPORTED_LOCATION_RELEASE instead. Since this can get quite tedious to do manually, you can have CMake generate this information (and a bunch of other convenient stuff) for you in a package script. The find mechanism for package scripts works slightly different under the hood, but the code in the CMakeLists.txt for executable will look just the same, a simple call to find_package(static_lib1). The main difference is that this call will then not dispatch to a hand-written find script, but to a package script that was automatically generated by CMake as part of the build process of static_lib1.
I guess I will leave this answer for posterity since only recently I have searched for a solution to this problem and found out that...
Since CMake 3.24 it is possible!
It is possible to override subsequent calls to find_package() with FetchContent_Declare() flag OVERRIDE_FIND_PACKAGE.
Your
add_subdirectory("path/to/static_lib1")
call has to be replaced in main_folder/CMakeLists.txt with:
include(FetchContent)
FetchContent_Declare(
static_lib1
SOURCE_DIR "path/to/static_lib1"
OVERRIDE_FIND_PACKAGE
)
Any calls to find_package(static_lib1) will call FetchContent_MakeAvailable() for you, virtually making it identical to add_subdirectory() call.
You can read more about OVERRIDE_FIND_PACKAGE in CMake documentation.