cmake ExternalProject cache overwritten - cmake

Hello I'm facing a problem regarding CMake and External Projects.
I set a compiler and some flags via CMAKE_CACHE_ARGS and/or CMAKE_ARGS this works the first time I run make but on any subsequent call the CMake Cache of the external project is rebuild (deleted) and the flags are not set accordingly to the flags I specified! So I wonder is there any workaround/way to specify the compiler only once to prevent rebuilding of the cache?
Following is a very basic test project which downloads and compiles GTest, first call to make compiles with Clang++ and the given flags, any following call to make will cause the CMake Cache to be rebuild without the proper flags being set!
cmake_minimum_version_required(VERSION 2.8.6)
project(test)
include(ExternalProject)
ExternalProject_Add(
GTest
SVN_REPOSITORY http://googletest.googlecode.com/svn/tags/release-1.7.0/
CMAKE_ARGS
-DCMAKE_CXX_COMPILER:STRING=clang++
-DCMAKE_CXX_FLAGS:STRING="\"-std=c++1y -stdlib=libc++\""
INSTALL_COMMAND "" # One can not install GTest so dont do anything here
LOG_DOWNLOAD 1
LOG_UPDATE 1
LOG_CONFIGURE 1
LOG_BUILD 1
)

I had the same problem, but with a different setup. Although this answer does not seem to apply to your setup it might be helpful for someone else.
In my case the issue was declaring the project with:
project(test LANGUAGES C)
The external project was a C++ project. Adding CXX to languages (or removing the option altogether, since C CXX is the default) solved the problem for me.

Related

add_subdirectory for cmake tensorflow lite fails on subsequent runs

I am trying to include tensorflow-lite in a project per the minimal example here: Build TensorFlow Lite with CMake. Specifically, I'm trying to add_subdirectory the CMakeLists.txt for tflite, as recommended.
This works when the project is first built, but if I change my top-level CMakeLists.txt for any reason (adding a test or linking something to a different target, say), then the build fails with the following:
-- Setting build type to Release, for debug builds use'-DCMAKE_BUILD_TYPE=Debug'.
CMake Warning at build/abseil-cpp/CMakeLists.txt:70 (message):
A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON for CMake
3.8 and up. We recommend enabling this option to ensure your project still
builds correctly.
-- Standard libraries to link to explicitly: none
-- The Fortran compiler identification is GNU 9.4.0
-- Could NOT find CLANG_FORMAT: Found unsuitable version "0.0", but required is exact version "9" (found CLANG_FORMAT_EXECUTABLE-NOTFOUND)
--
-- Configured Eigen 3.4.90
--
-- Proceeding with version: 2.0.6.v2.0.6
-- CMAKE_CXX_FLAGS: -std=c++0x -Wall -pedantic -Werror -Wextra -Werror=shadow -faligned-new -Werror=implicit-fallthrough=2 -Wunused-result -Werror=unused-result -Wunused-parameter -Werror=unused-parameter -fsigned-char
CMake Error at build/cpuinfo/CMakeLists.txt:262 (ADD_SUBDIRECTORY):
ADD_SUBDIRECTORY not given a binary directory but the given source
directory "/opt/------/workspace/------/build/clog-source"
is not a subdirectory of
"/opt/------/workspace/------/build/cpuinfo". When
specifying an out-of-tree source a binary directory must be explicitly
specified.
CMake Error at build/cpuinfo/CMakeLists.txt:265 (SET_PROPERTY):
SET_PROPERTY could not find TARGET clog. Perhaps it has not yet been
created.
-- Configuring incomplete, errors occurred!
See also "/opt/------/workspace/------/build/CMakeFiles/CMakeOutput.log".
See also "/opt/------/workspace/------/build/CMakeFiles/CMakeError.log".
(Those dashes aren't real paths, they're just to mask sensitive info.)
Just to reiterate, it DOES configure and build correctly the first time, but reruns of cmake .. will fail.
I've tried this on a couple of platforms and got the same result. You should be able to reproduce with a minimal CMakeLists.txt containing add_subdirectory and some helloworld target to link tensorflow-lite.
I tried giving the add_subdirectory for clog a binary location but just got a cascade of new errors, and at that point my CMake know-how definitely runs out.
The issue is due to the same cmake variable CLOG_SOURCE_DIR used in both xnnpack and cpuinfo.
In xnnpack, it uses a cmake script to download, configure and build the clog.
In cpuinfo, it add as a subdirectory.
So they use different ways to add dependency. We need to fix this issue in either xnnpack or cpuinfo but as a walkaround, we can change the CLOG_SOURCE_DIR in either project to a different name (e.g. CLOG_SOURCE_DIR1) then this problem will go away.

cmake not rebuilding a non-download external project after manually editing its sources

I'm working on some modifications to the openEMS project. This project uses cmake to build all of its components. The top level CMakeLists.txt file contains the following:
# ...
ExternalProject_Add( openEMS
DEPENDS fparser CSXCAD
SOURCE_DIR ${PROJECT_SOURCE_DIR}/openEMS
CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DFPARSER_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DCSXCAD_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DWITH_MPI=${WITH_MPI} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
)
# ...
Inside the openEMS directory, there's another CMakeLists.txt with the following:
# ...
set(SOURCES
openems.cpp
)
# ...
add_library( openEMS SHARED ${SOURCES})
# ...
After building the project successfully once, make does not rebuild anything when, for example, openems.cpp is modified. Why?
$ mkdir build
$ cd build
$ cmake -DBUILD_APPCSXCAD=NO
$ make
[builds all files]
$ touch ../openEMS/openems.cpp
$ make
[ 33%] Built target fparser
[ 66%] Built target CSXCAD
[100%] Built target openEMS
(noting is built)
I have checked and the modification date of openems.cpp is newer than the target. Even deleting the produced library files and binaries, both in the install directory and in the build directory, does not cause it to rebuild anything. The only way I can get it to rebuild is by deleting everything in the build directory and re-running cmake which, of course, rebuilds everything.
This looks like a case of the following. Quoting from the docs for ExternalProject_Add at the section titled "Build Step Options":
BUILD_ALWAYS <bool>
Enabling this option forces the build step to always be run. This can be the easiest way to robustly ensure that the external project's own build dependencies are evaluated rather than relying on the default success timestamp-based method. This option is not normally needed unless developers are expected to modify something the external project's build depends on in a way that is not detectable via the step target dependencies (e.g. SOURCE_DIR is used without a download method and developers might modify the sources in SOURCE_DIR).
If that's the case, the solution would be to add the BUILD_ALWAYS argument to the ExternalProject_Add call like.
ExternalProject_Add( openEMS
DEPENDS fparser CSXCAD
SOURCE_DIR ${PROJECT_SOURCE_DIR}/openEMS
CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DFPARSER_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DCSXCAD_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DWITH_MPI=${WITH_MPI} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
BUILD_ALWAYS TRUE
)
If you confirm that this solves the issue, you might want to raise this as an issue to the maintainers of openEMS.
Also note that since the external project there is using CMake as a buildsystem, you could also add the CONFIGURE_HANDLED_BY_BUILD TRUE to the argument list. See the docs for more info.
Edit: The asker opened a GitHub Pull-Request.

CMake, multiple targets (asan tsan..) without having to recompile everything

Goal
I want to define several targets:
make msan: compiles the code with clang with memory sanitizer
make tsan: compiles the code with clang with thread sanitizer
make : compiles the code with gcc
And be able to easily switch between them.
For example I don't want each time I switch rebuild all my objects, (I will have to do it the first time of course, but later if I modify a file and I do make and then make asan it should recompile only this file for each target)
What I have done so far
I have managed to create these targets and from the root directory, but each time I have to do a make clean and recompile.
option(CLANG_MSAN "Enable Clang memory sanitizer" OFF)
if (CLANG_MSAN)
set (CMAKE_CXX_FLAGS "-g -fsanitize=address -fno-omit-frame-pointer")
endif()
add_custom_target(asan
COMMAND ${CMAKE_COMMAND}
-DCLANG_MSAN=ON
-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_C_COMPILER=clang)
Is it possible to do such a thing with CMake?
Yes, but use multiple build directories:
Create a build directory per configuration.
Configure your project in your build directories with the parameters you need. E.g. cmake -DCMAKE_COMPILER=clang -DCMAKE_C_FLAGS="-fsanitize=thread" .. or the stuff from your question.
If you switch the build directory, you changed your setup.
This implies out-of-source builds, which are encouraged by CMake anyway.
I believe you should be able to achieve this with the ExternalProject module. You could add three external projects, one for msan, one for tsan, and one for the basic GCC build. The two sanitiser builds would be marked as EXCLUDE_FROM_ALL 1.
The CMakeLists for all three of them could share the common part via include().
Something like this:
Root CMakeLists.txt
ExternalProject_Add(msan
EXCLUDE_FROM_ALL 1
SOURCE_DIR msan
CMAKE_GENERATOR ...
)
ExternalProject_Add(tsan
EXCLUDE_FROM_ALL 1
SOURCE_DIR tsan
CMAKE_GENERATOR ...
)
ExternalProject_Add(normal
SOURCE_DIR src
CMAKE_GENERATOR ...
)
src/CMakeLists.txt
include(common.cmake)
src/common.cmake
# Normal CMake code for your project
add_library(...)
msan/CMakeLists.txt
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address -fno-omit-frame-pointer")
include(../src/common.cmake)

CMake dependencies: force recompile on external library change

I'm trying to correctly manage a dependency of a target on a externally built library, and somehow I'm not succeeding. I have read tutorials, posts and examples aplenty and yet, since I'm new to CMake, I guess I'm missing some obvious thing.
Setup is as follows. An external library built in another (CMake unsupported) language produces a libadatest.a. I've used ExternalProject_Add for this. Then, there is another regular C target that uses this lib. Everything works fine, but if I change the original lib, even if I recompile it, the C target is not recompiled. Here is a complete sample. I'm using CMake 2.8.12:
cmake_minimum_required(VERSION 2.8)
include(ExternalProject)
ExternalProject_Add(
AdaTestExternal # Not important
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
BUILD_COMMAND gprbuild -P${CMAKE_CURRENT_SOURCE_DIR}/adalibtest -XOBJ_DIR=${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY} -XLIB_DIR=${CMAKE_CURRENT_BINARY_DIR}
ALWAYS 1 # Force build, gprbuild will take care of dependencies
# BUILD_ALWAYS 1 # For 3.0 higher versions?
INSTALL_COMMAND ""
)
add_custom_target(AdaTest DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/libadatest.a)
link_directories(${CMAKE_CURRENT_BINARY_DIR}) # Needed or won't find it
add_executable(main_ada main.c)
add_dependencies(main_ada AdaTest) # We must depend on the final output lib
target_link_libraries(main_ada adatest)
What I've attempted is to create an intermediate custom target which depends on the actual library, and in turn make the main C target depend on this target.
When I remove the externally built library (libadatest.a), that's properly externally recompiled but the main executable is not re-linked. Plainly seen in that the timestamp of the library is fresher than the executable which uses it.
I've also tried this instead of the custom target, with same negative result:
add_library(AdaTest
UNKNOWN IMPORTED
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/libadatest.a)
Found the proper solution (which was, as expected, simple) in this old post: http://www.cmake.org/pipermail/cmake/2010-November/041072.html
The gist is to use the actual file in target_link_libraries, so its timestamp is checked. So no need for intermediate or custom dependencies:
set(AdaTestLib ${CMAKE_CURRENT_BINARY_DIR}/libadatest.a)
add_executable(main_ada main.c)
add_dependencies(main_ada AdaTestExternal)
target_link_libraries(main_ada ${AdaTestLib})

CMake depend.make file empty

I start using CMake to build my c++ source files, I see a strange comportament when I build inicially:
'cmake ../' will gerate the directory structure
'make' will build all
any successive make command will build nothing, as expected
'cmake ../' will apparent do nothing
'make' WILL REBUILD all
any successive make command will build nothing, as expected
There is my CMakelists.txt:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-Wall -pipe")
set(var_target CommonBase)
set(var_path_source base)
project(Prj_${var_target})
file(GLOB_RECURSE var_sources ${var_path_source}/*.cpp)
add_library(${var_target} SHARED ${var_sources})
install(TARGETS ${var_target} DESTINATION ${PROJECT_SOURCE_DIR}/install)
Looking better, at first 'cmake ../' command the file 'CMakeFiles/CommonBase.dir/depend.make' is empty, and the successive make command will insert the list of file dependencies
There is something wrong with my CMakelists.txt?
Thanks
There are a couple of issues here.
The actual cause of your problem is having the line set(CMAKE_CXX_FLAGS ...) before the project command.
The project command does quite a lot of work the first time it is run, and actually clears out this variable as a side-effect. So on your first run of CMake, the compiler flags are empty, and thereafter always contain what you set them to. (It's only the second time you run CMake which causes make to recompile all, not subsequent runs of CMake).
Try wrapping your project call with messages to see the effect:
message("CMAKE_CXX_FLAGS - ${CMAKE_CXX_FLAGS}")
project(Prj_${var_target})
message("CMAKE_CXX_FLAGS - ${CMAKE_CXX_FLAGS}")
Delete your CMakeCache.txt file (in your build root), then just run cmake .. repeatedly.
To fix this, move your set(CMAKE_CXX_FLAGS ...) to after the project command.
The second issue is that it's not recommended to set CMAKE_CXX_COMPILER in a CMakeLists.txt. Have a look at the comment below "Setting default compiler in CMake", and also the link there to CMake's FAQ entry How do I use a different compiler?