I have the following directory structure:
.
├── CMakeLists.txt
├── generator
│ ├── CMakeLists.txt
│ └── main.cpp
├── include
└── src
├── CMakeLists.txt
└── mylib.cpp
I would like to build generator, then use generator to generate a source file that will be used to build mylib. I tried this:
generator/CMakeLists.txt:
add_executable(gen main.cpp)
add_custom_command(
OUTPUT
${CMAKE_BINARY_DIR}/generated.cpp
DEPENDS
gen
COMMAND
${CMAKE_BINARY_DIR}/gen -d /tmp
VERBATIM
)
src/CMakeLists.txt:
add_library(py-cppast
${CMAKE_BINARY_DIR}/generated.cpp
mylib.cpp)
CMakeLists.txt:
cmake_minimum_required(VERSION 3.1.2)
project(my-project)
add_subdirectory(generator)
add_subdirectory(src)
However, the command is not executed. Instead, I just get the error:
CMake Error at src/CMakeLists.txt:2 (add_library):
Cannot find source file:
/home/....(the cmake binary dir)..../generated.cpp
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
How can I tell cmake to execute the program I'm building with it? Is this even possible in a single build?
The problem comes from the fact that you are generating the file generated.cpp in one directory and then trying to add it to a target defined in a different directory. CMake only supports adding generated files to targets defined in the same directory scope. The add_custom_command() documentation explicitly mentions this restriction.
You probably want to move the generation of generated.cpp into the src directory. You should also use just the gen target name to refer to the executable to run, not ${CMAKE_BINARY_DIR}/gen which is not going to be correct with all CMake generator types. It would also be better style to use the current binary directory rather than the top level binary directory as the output dir. Your src/CMakeLists.txt should look something like this:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated.cpp
DEPENDS gen
COMMAND gen -d /tmp
VERBATIM
)
add_library(py-cppast
${CMAKE_CURRENT_BINARY_DIR}/generated.cpp
mylib.cpp
)
CMake will automatically substitute the location of the gen target for you, even though it was defined in a different directory. There are some further subtleties to be aware of when using generated sources, particularly relating to dependencies. You may find this article helpful to fill in some gaps.
Related
Consider a simple scenario where my cmake project adds a dependency as a subdirectory:
.
├── CMakeLists.txt
├── src
├── include
│
└── externals
└── BAR
├── CMakeLists.txt
├── src
└── include
The main CMakeLists.txt is something like:
cmake_minimum_required(VERSION 3.0)
project(FOO)
add_subdirectory(externals/BAR)
set(SOURCES ${CMAKE_SOURCE_DIR}/src/foo.cpp
${CMAKE_SOURCE_DIR}/include/bar.hpp)
add_library(${PROJECT_NAME} SHARED ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_SOURCE_DIR}/include # this works
${BAR_INCLUDE_DIR}) # this does not
The problem is, the include directories of the added project are not accessable from FOO project.
BAR is a huge dependency with its own sub directories. Its root cmake uses INCLUDE_DIRECTORIES command (instead of target_include_directories). It then does some FILE ( GLOB headers and use them when triggering make install
I am aware that there are many questions regarding subdirectories in cmake, however, in my case cannot modify the CMakeLists.txt in the subdirectory. It's a git submodule that gets updated constantly and it's a pain to modify it constantly.
How can I access BAR's include directories (and later its libraries) without changing its cmakes?
P.S. BAR gets compiled properly and shared library appears in the build folder.
My C++ project doggo has a doggo/external/ directory for third-party code. Currently it contains gtest and a CMakeLists.txt:
# Google gtest for unit testing.
add_subdirectory(gtest)
message("gtest include dir: ${gtest_SOURCE_DIR}")
include_directories(${gtest_SOURCE_DIR})
My top-level doggo/CMakeLists.txt contains the line add_subdirectory(external) to find and build the third-party libraries. Everything works like a charm -- I can include gtest with #include <gtest/gtest.h>. Now I'd like to add the randomkit C library to doggo/external/, as is done here: randomkit from numpy.
How can I get randomkit to build in my doggo/external/ dir? What should the doggo/external/CMakeLists.txt look like?
I should then be able to include the C headers for use in my x.cpp files by including the headers inside an extern "C" { ... } block (details here).
UPDATE: How do I install randomkit here?
I've included a CMakeLists.txt entry like that above but for randomkit, and the directory looks like,
external
├── CMakeLists.txt
├── gtest
│ └── ...
└── randomkit
├── CMakeLists.txt
├── distributions.c
├── distributions.h
├── randomkit.c
└── randomkit.h
and the randomkit/CMakeLists.txt:
project(randomkit)
file(GLOB SOURCES "*.c")
add_library(randomkit SHARED ${SOURCES})
INSTALL(
DIRECTORY ${CMAKE_SOURCE_DIR}/
DESTINATION "/usr/local/"
#DESTINATION ""
FILES_MATCHING PATTERN "*.h*")
(second DESTINATION commented out to show I tried that as well)
Yet when I run the build steps for my top-level project doggo I get an error trying to #include <randomkit/distributions.h>:
doggo/src/random_fooz.cpp:10:37: fatal error: randomkit/distributions.h: No such file or directory
UPDATE 2: doggo/CMakeLists.txt:
project(doggo)
# Find and build third-party libraries
add_subdirectory(external)
# Add source dirs to the search path so cmake can find headers
include_directories(${CMAKE_SOURCE_DIR}/include/)
# Collect source files and build
file(GLOB_RECURSE doggo_srcs ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_library(doggo ${doggo_srcs})
# Setup executables
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/)
add_subdirectory(exec)
# Tests
add_subdirectory(test)
In the randomkit/CMakeLists.txt write:
project(randomkit)
file(GLOB SOURCES "*.c")
add_library(randomkit SHARED ${SOURCES})
target_include_directories(randomkit PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
INSTALL(
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
DESTINATION "include" # this a the subdirectory with ${CMAKE_INSTALL_PREFIX}
FILES_MATCHING PATTERN "*.h*")
In the main CMakeLists.txt, you do:
add_library(doggo ${doggo_srcs})
target_link_libraries(doggo PUBLIC randomkit)
target_include_directories(doggo PUBLIC ${CMAKE_SOURCE_DIR}/include/)
Don’t use include_directories.
Now, because the randomkit target has the PUBLIC property with the right include directories, those include directories will be automatically used when building the doggo library. And again, because the doggo library has include directories and libraries in its public interface, executables that you link to doggo will automatically be linked to these libraries, and find their include files.
Note that the INSTALL command in randomkit/CMakeLists.txt is only executed when you actually run the install target. When building, the include files must be found in the source tree.
I am using CMake 3.10.1 and trying to use CPack to generate archives for a library and I cannot get it to add the interface include directory to the archive.
The library and the generated export files are added as expected, however the include directory (added using target_include_directories(... PUBLIC ...) is missing entirely.
The CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(Test VERSION 1.0.0 LANGUAGES CXX)
add_library(${PROJECT_NAME} SHARED foo.cpp) #add sources and executable
target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
$<INSTALL_INTERFACE:inc>
)
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}
INCLUDES DESTINATION inc
PUBLIC_HEADER DESTINATION inc
LIBRARY DESTINATION lib
)
install(EXPORT ${PROJECT_NAME} DESTINATION .)
include(CPack)
The contents of my source dir:
├── CMakeLists.txt
├── foo.cpp
└── inc
└── foo.h
The contents of the tgz generated by cpack -G TGZ .
├── lib
│ └── libTest.so
├── Test.cmake
└── Test-noconfig.cmake
Any ideas why it could be missing the inc directory?
Generator-like expression $<INSTALL_INTERFACE> used in the target_include_directories() command by itself doesn't install corresponded directory. You need to install this directory manually (with install(FILES) or install(DIRECTORY)).
Expression $<INSTALL_INTERFACE> specifies interface include directory for the target in the config file, which exports install tree (see install(EXPORT) command).
Expression $<BUILD_INTERFACE> specified interface include directory for the target in the project itself, and in the config file which exports build tree (see EXPORT() command).
But these expressions doesn't enforce $<BUILD_INTERFACE> directory to be copied into $<INSTALL_INTERFACE> one on installation. As opposite, content of this directories usually differs: aside from header files for outer use, installed into $<INSTALL_INTERFACE> directory, a directory $<BUILD_INTERFACE> may contain header files for project's internal use, which are not installed.
Assume I have a project of the following directory structure:
myproject
├── .git [...]
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── foo.cc
└── foo.h
If in src/foo.cc I include the header file like #include "foo.h" and then run Google's cpplint.py on it, it complains with
src/foo.cc:8: Include the directory when naming .h files [build/include] [4]
So I include it as #include "./foo.h". Now I get another complaint:
src/foo.cc:8: src/foo.cc should include its header file src/foo.h [build/include] [5]
However, if I include it as #include "src/foo.h", the compiler won't find it, with my current setup of CMake. This is how my two CMakeLists.txt files look like:
CMakeLists.txt:
project(myproject)
add_subdirectory(src)
src/CMakeLists.txt:
set(SRCS foo.cc)
add_executable(foo ${SRCS})
Is the way I'm using CMake somehow fundamentally wrong? Should I remove the src/CMakeLists.txt file entirely, and specify all source files in the base CMakeLists.txt with their full path?
Or should I simply ignore cpplint's complaints, as they don't really fit to how CMake projects are to be set up?
Add include_directories(${CMAKE_SOURCE_DIR}) in your top level CMakeLists.txt, like Wander suggested:
project(myproject)
include_directories(${CMAKE_SOURCE_DIR})
add_subdirectory(src)
I'm trying to learn CMake from http://www.cmake.org/cmake/help/cmake_tutorial.html and running into trouble with the first step itself of running a simple file tutorial.cpp.
The issue is that when I have this command in my CMakeLists.txt file
add_executable(Tutorial tutorial.cpp)
it builds fine.
However, when I change it to
add_executable(Tutorial tutorial.cxx)
It gives the following error
-- Configuring done
CMake Error at src/CMakeLists.txt:6 (add_executable):
Cannot find source file:
tutorial.cxx
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
-- Build files have been written to: /home/vaisagh/workspace/Test/build
My directory structure is like this:
.
├── build
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── tutorial.cpp
2 directories, 3 files
CMakeLists.txt
#Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.8.11)
#Name your project here
project(Tutorial)
add_subdirectory(src)
src/CMakeLists.txt
#Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.8.11)
add_executable(Tutorial tutorial.cxx)
Tried extensions .c .C... Indicates that CMake tried to search for tutorial.cxx.c, tutorial.cxx.C, etc.
The source filename given to add_executable must match the actual filename on disc.
Rename tutorial.cpp to tutorial.cxx -or-
Change add_executable(Tutorial tutorial.cxx) to add_executable(Tutorial tutorial.cpp)