file structure
├── a_lib
│ ├── a.cpp
│ └── a.h
├── CMakeLists.txt
└── main.cpp
CmakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(untitled)
set(CMAKE_CXX_STANDARD 11)
add_library(a_lib SHARED a_lib/a.cpp)
target_include_directories(a_lib PUBLIC a_lib/)
add_executable(untitled main.cpp)
target_link_libraries(untitled a_lib)
But every time I build the a_lib will be rebuilt when a_lib is not changed.
cmake --build /home/autocar/Workspace/untitled/cmake-build-debug --target untitled -- -j 4
[ 50%] Built target a_lib
[100%] Built target untitled
So what should I do, if I do not want to rebuild the linked library every time. It takes a long time when a_lib builds every time even without any changes.
Just one addition to arrowd's answer:
If you want to completely avoid check if any target is up to date, you can issue the following command:
cmake --build /home/autocar/Workspace/untitled/cmake-build-debug --target untitled/fast -- -j 4
Note that --target untitled is changed into --target untitled/fast.
You can add "/fast" to any target mentioned in CMakeLists.txt to trigger compilation without any additional checks. On the other hand, be extremely cautious, since this allows you create inconsistent results, in case when sources for a_lib are changed, and target a_lib should be compiled/linked as well.
Judging from this output
cmake --build /home/autocar/Workspace/untitled/cmake-build-debug --target untitled -- -j 4
[ 50%] Built target a_lib
nothing's actually gets rebuilt. CMake just checks that this target is up to date.
The compilation takes place when CMake prints Building CXX object a.cpp.o and linking is performed when Linking CXX library a_lib.so pops out. If you don't see these messages, the library doesn't get rebuilt.
Related
Introduction
Using CMake, I am trying to build a library using a special make target. To this end, I use the EXCLUDE_FROM_ALL argument to ensure that the library is not built by running make (which defaults to make all). Unfortunately, the EXCLUDE_FROM_ALL option seems to be ignored by cmake.
Consider the following file tree:
.
├── CMakeLists.txt
├── foo
│ ├── CMakeLists.txt
│ ├── headers
│ │ └── foo.h
│ └── src
│ └── foo.cpp
└── src
└── main.cpp
4 directories, 5 files
In this file tree, you can see that I basically have two parts:
The foo library, for which all files are located in ./foo/.
The main executable, for which the source code is located in ./src/main.cpp.
Below, I will further explain these two parts and the behaviour I am observing.
The foo library
First of all, the header code located in ./foo/headers/foo.h is:
#ifndef _FOO_H_
#define _FOO_H_
#include <iostream>
void foo(void);
#endif // _FOO_H_
The corresponding source code, located in ./foo/src/foo.cpp, is:
#include "foo.h"
void foo(void) {
std::printf("Hello foo!\n");
}
As you can see, the foo library only contains the function foo(). This function simply prints Hello, foo! to the terminal. To build the foo library, I have the following CMakeLists.txt file defined (in ./foo/CMakeLists.txt):
cmake_minimum_required(VERSION 3.10)
project(foo
LANGUAGES CXX
)
# Create a foo library target
add_library(foo EXCLUDE_FROM_ALL
"src/foo.cpp"
)
target_include_directories(foo
PUBLIC "headers"
)
Note that I use the EXCLUDE_FROM_ALL argument in the add_library() function.
To test the behaviour of the EXCLUDE_FROM_ALL argument, I will now build the foo library as a stand-alone (using the previously shown CMakeLists.txt). Starting from the top directory (.), I use the following workflow:
$ cd foo
$ mkdir build
$ cd build
$ cmake ..
After this is finished, I run the make command:
$ make
(nothing happens)
As expected, nothing happens (since the foo library is excluded from the all target). Now, when I use make foo, I get the following output:
$ make foo
Scanning dependencies of target foo
[ 50%] Building CXX object CMakeFiles/foo.dir/src/foo.cpp.o
[100%] Linking CXX static library libfoo.a
[100%] Built target foo
So far, so good. Before moving on to building the main executable, I completely remove the ./foo/build directory and go back to the top-level directory:
$ cd ..
$ rm -rf build
$ cd ..
The main executable
The source code for the main executable is located in ./src/main.cpp:
#include "foo.h"
int main() {
foo();
return 0;
}
The top-level CMakeLists.txt contains:
cmake_minimum_required(VERSION 3.10)
project(TestProject
LANGUAGES CXX
)
# Include the foo library
add_subdirectory("foo" EXCLUDE_FROM_ALL)
# Create the main executable
add_executable(TestProject
"src/main.cpp"
)
target_link_libraries(TestProject
PRIVATE foo
)
Note that I again use the EXCLUDE_FROM_ALL argument, but now for the add_subdirectory() function.
To generate a makefile for the main executable, I use the following workflow:
$ mkdir build
$ cd build
$ cmake ..
When I now run make, I get the following output:
$ make
Scanning dependencies of target foo
[ 25%] Building CXX object foo/CMakeFiles/foo.dir/src/foo.cpp.o
[ 50%] Linking CXX static library libfoo.a
[ 50%] Built target foo
Scanning dependencies of target TestProject
[ 75%] Building CXX object CMakeFiles/TestProject.dir/src/main.cpp.o
[100%] Linking CXX executable TestProject
[100%] Built target TestProject
As you can see, it first builds the foo library. However, this is not what I expected! I explicitly stated to exclude the foo library from the all target. Hence, I would expect the need to first run make foo before running make.
This brings me to my main question(s): does someone know why it ignores the EXCLUDE_FROM_ALL option in the add_subdirectory() function in the top-level CMakeLists.txt? It did work when I built the foo library as a stand-alone. Is this a bug in cmake? If not, how do I achieve my expected behaviour (i.e. the need to run make foo before running make)?
This is not a bug. CMake does not include the foo lib in the all target directly. It does however add the foo target as dependency to TestProject and since TestProject is included in the all target, foo gets built too, if you build all.
This needs to be done this way. How else would you be able to link the foo function into TestProject?
If you want to use a lib that is not built as part of all, you need to use a imported lib. Doing this is and including the lib in the project seems a bit nonsensical though, but here you go.
add_library(foo STATIC EXCLUDE_FROM_ALL
"src/foo.cpp"
)
cmake_minimum_required(VERSION 3.10)
project(TestProject
LANGUAGES CXX
)
# Include the foo library
add_subdirectory("foo" EXCLUDE_FROM_ALL)
# Create the main executable
add_executable(TestProject
"src/main.cpp"
)
# add copy of foo as imported lib
add_library(foo_imported STATIC IMPORTED)
target_include_directories(foo_imported INTERFACE $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(foo_imported PROPERTIES IMPORTED_LOCATION $<TARGET_FILE:foo>)
target_link_libraries(TestProject
PRIVATE foo_imported
)
I have a simple shared library libfool2.so with installed header fool2.h which are not from a CMake project. My project my_temp1 depends on fool2 so I write a FindFool2.cmake to make an imported target:
find_path(Fool2_INCLUDE_DIR fool2.h PATH_SUFFIXES fool2)
find_library(Fool2_LIB fool2)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Fool2
REQUIRED_VARS Fool2_INCLUDE_DIR Fool2_LIB
)
if(Fool2_FOUND AND NOT TARGET Fool2::Fool2)
add_library(Fool2::Fool2 SHARED IMPORTED)
set_target_properties(Fool2::Fool2 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Fool2_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${Fool2_LIB}"
)
endif()
The CMakeLists.txt for my_temp1 project is:
cmake_minimum_required(VERSION 3.3)
project(my_temp1)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_modules)
# FindFool2.cmake is in ${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_modules
find_package(Fool2 REQUIRED)
if (TARGET Fool2::Fool2)
message(STATUS "target found")
endif()
add_executable(my_temp1 main.cpp)
target_link_libraries(my_temp1 Fool2::Fool2)
Now
$ tree ../__install
../__install/
├── include
│ └── fool2
│ ├── fool2.h
│ └── version.h
└── lib
└── libfool2.so
$ tree .
.
├── cmake
│ └── cmake_modules
│ └── FindFool2.cmake
├── CMakeLists.txt
└── main.cpp
$ cmake -H. -B_builds -DCMAKE_INSTALL_PREFIX=../__install
# some output omitted
-- target found
-- Configuring done
-- Generating done
-- Build files have been written to: /OMITTED/my_temp1/_builds
$ cmake --build _builds
CMakeFiles/my_temp1.dir/build.make:82: *** target pattern contains no '%'. Stop.
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/my_temp1.dir/all' failed
make[1]: *** [CMakeFiles/my_temp1.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
$ head -n 85 _builds/CMakeFiles/my_temp1.dir/build.make | tail -n 10
# External object files for target my_temp1
my_temp1_EXTERNAL_OBJECTS =
my_temp1: CMakeFiles/my_temp1.dir/main.cpp.o
my_temp1: CMakeFiles/my_temp1.dir/build.make
my_temp1: Fool2::Fool2-NOTFOUND
my_temp1: CMakeFiles/my_temp1.dir/link.txt
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/OMITTED/my_temp1/_builds/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Linking CXX executable my_temp1"
$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/my_temp1.dir/link.txt --verbose=$(VERBOSE)
The command $ cmake -H. -B_builds -DCMAKE_INSTALL_PREFIX=../__install finds fool2 because find_* commands searches in the CMAKE_INSTALL_PREFIX as well.
But why is there weird output my_temp1: Fool2::Fool2-NOTFOUND in build.make?
CMake version is 3.11.3
For IMPORTED library target value -NOTFOUND corresponds to absent IMPORTED_LOCATION property, corresponded to the library's path. You need to set that property for correctly work with IMPORTED target.
If you want CMake target to be a placeholder just for link with other libraries, use INTERFACE library target instead: such library target doesn't have library location.
I'm encountering an annoying error in CMake where the following conditions hold:
A target name is identical to name of the directory defining the target.
I am using the RUNTIME_OUTPUT_DIRECTORY property for the target.
Under these conditions, I get the errors:
Linking CXX executable .
/usr/bin/ld: cannot open output file .: Is a directory
CMake seems to be trying to build a target named . , apparently trying to refer to the current directory name rather than the desired target name.
Here's a trivial example. My file tree is:
/tmp/example$ tree
.
├── build
└── src
├── CMakeLists.txt
└── hello_world
├── CMakeLists.txt
└── HelloWorld.cpp
src/CMakeLists.txt:
set (ARBITRARY_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(hello_world)
src/hello_world:
add_executable(hello_world HelloWorld.cpp)
set_property(TARGET hello_world PROPERTY RUNTIME_OUTPUT_DIRECTORY ${ARBITRARY_OUTPUT_DIR})
...and HelloWorld.cpp itself is a trivial Hello World program, with a main() method.
I run:
/tmp/example/build$ cmake ../src/ -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8 -G"Unix Makefiles"
/tmp/example/build$ make VERBOSE=1
And I get:
[ 50%] Building CXX object hello_world/CMakeFiles/hello_world.dir/HelloWorld.o
cd /tmp/example/build/hello_world && /usr/bin/g++-4.8 -O3 -DNDEBUG -o CMakeFiles/hello_world.dir/HelloWorld.o -c /tmp/example/src/hello_world/HelloWorld.cpp
[100%] Linking CXX executable .
cd /tmp/example/build/hello_world && /usr/bin/cmake -E cmake_link_script CMakeFiles/hello_world.dir/link.txt --verbose=1
/usr/bin/g++-4.8 -O3 -DNDEBUG CMakeFiles/hello_world.dir/HelloWorld.o -o . -rdynamic
/usr/bin/ld: cannot open output file .: Is a directory
collect2: error: ld returned 1 exit status
As you can see, CMakeFiles/hello_world.dir/link.txt sets the linking target as -o . , which obviously won't work.
Is this a bug in CMake, or am I doing something wrong? Is there some workaround for this?
My tools are:
cmake version 3.5.1
Ubuntu 16.04 LTS (Xenial Xerus)
g++-4.8
Your top-level build directory contains hello_world directory because of command add_subdirectory(hello_world).
By setting RUNTIME_OUTPUT_DIRECTORY property to top-level build directory, you want to create executable file with name hello_world there.
But in single directory it is impossible to have both file and directory with the same name.
You need to rename either subdirectory or executable or change directory to place executable.
I have a project with a structure
├── CMakeLists.txt
├── mzl.c
├── mzl.h
└── tests
├── CMakeLists.txt
├── mzl-communication-test.c
├── mzl-setup-test.c
├── mzl-test-errors.c
└── mzl-test-errors.h
Where the top directory CMakeLists.txt file is
project(mzl)
cmake_minimum_required(VERSION 2.8)
add_subdirectory(tests)
# Enable testing for the project
enable_testing()
# Find zmq
find_library(ZMQ_LIB zmq REQUIRED)
message(STATUS "ZMQ Library: ${ZMQ_LIB}")
# Find threading library
set(CMAKE_THREAD_PREFER_PTHREAD ON)
find_package(Threads REQUIRED)
message(STATUS "Threading Library: ${CMAKE_THREAD_LIBS_INIT}")
# Set include directories for headers
set (
MZL_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}
CACHE STRING "MZL Include Directories"
)
include_directories(${MZL_INCLUDE_DIRS})
# Set source files
set (
MZL_SRC_FILES
mzl.c
)
# Add library
add_library(${PROJECT_NAME} STATIC ${MZL_SRC_FILES})
# Link to zmq
target_link_libraries(${PROJECT_NAME} ${ZMQ_LIB} ${CMAKE_THREAD_LIBS_INIT})
and tests/CMakeLists.txt is
# Use MZL Source Directories (mzl headers are in top directory)
include_directories(${CMAKE_SOURCE_DIR})
# Variable from here is empty
message(STATUS "MZL Include Directories: ${MZL_INCLUDE_DIRS}")
# Files common to all tests
set ( TEST_COMMON_SOURCES
mzl-test-errors.c
)
# Library setup/shutdown testing
set(SETUP_TEST_NAME mzl-setup-test)
add_executable(${SETUP_TEST_NAME} ${TEST_COMMON_SOURCES} ${SETUP_TEST_NAME}.c)
target_link_libraries(${SETUP_TEST_NAME} ${PROJECT_NAME} ${ZMQ_LIB})
add_test(${SETUP_TEST_NAME} ${SETUP_TEST_NAME})
# Communcations test
set(COMMUNICATION_TEST_NAME mzl-communication-test)
add_executable(${COMMUNICATION_TEST_NAME} ${TEST_COMMON_SOURCES}
${COMMUNICATION_TEST_NAME}.c)
target_link_libraries(${COMMUNICATION_TEST_NAME} ${PROJECT_NAME}
${CMAKE_THREAD_LIBS_INIT} ${ZMQ_LIB})
add_test(${COMMUNICATION_TEST_NAME} ${COMMUNICATION_TEST_NAME})
Everything worked fine before I added the second test mzl-communication-test. After adding it and the lines in the tests/CMakeLists.txt after # Communications test, running ctest did nothing extra -- it still only ran the first test.
After deleting the build directory and running cmake again, I get no errors for the initial CMake run, but running make runs CMake again, resulting in an error with CMake:
CMake Error: Parse error in cache file build/CMakeCache.txt. Offending entry: include
followed by a Make error:
Makefile:203: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
Running make again results in everything being built, including the tests; however, running ctest results in
Test project build
No tests were found!!!
The issue seems to be with something that I am doing with CMake, but can't figure out what to do from here as I can't see anything that I'm doing differently than when it was originally working. Even my last commit to git, which was working when I committed it, is no longer working.
You need to move the enable_testing() call to be before you do add_subdirectory(tests)
# Enable testing for the project
enable_testing()
add_subdirectory(tests)
I'm trying to configure CMake and ninja as a build system for my project. Except the app itself I have an extra executable for unit tests powered by gtest. I thought it would be nice to have them executed automatically whenever they are built. Here's how I made it:
├── build
└── source
├── CMakeLists.txt
├── main.cc
└── ut
├── CMakeLists.txt
├── gtest
│ ├── ...
└── ut.cc
source/CMakeLists.txt...
cmake_minimum_required (VERSION 2.6)
project (trial)
add_subdirectory(ut)
add_executable(trial main.cc)
...and source/ut/CMakeLists.txt:
add_subdirectory(gtest)
include_directories ("gtest/include")
add_executable(ut ut.cc)
target_link_libraries(ut LINK_PUBLIC gtest_main)
add_custom_target(run_uts
COMMAND ut
DEPENDS ut
WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
)
Now when I build it, i.e.:
cd build
cmake -GNinja ../source
ninja run_uts
It works fine except that the output is colorless. When I run the ut binary by hand, i.e. build/ut/ut I get nice green and red colors. The colors are also there when I use Unix Makefiles as a genrator for CMake.
Since I'm only learning CMake, is there something I missed or is it an issue with Ninja?
I assume your automated code runs a gtest executable and directs the output to a file. By default, gtest adds color sequences only when sending output to a terminal. In order to force it to add color sequences to output sent to a file or a pipe, run your test executable with the --gtest_color=yes option.