I have a CMake project with the following directory structure:
CMakeLists.txt
A/CMakeLists.txt
B/CMakeLists.txt
A and B both describe shared libraries, and B depends upon A.
Calling cmake on the entire project gives no problems. Neither does building A, but building B tells me it misses symbols from A. This makes sense, and so I solved that by adding target_link_libraries(B A) to B/CMakeLists.txt.
However, when I call cmake now, I get errors about B/CMakeLists.txt not being able to find source files from A. Apparently, to solve this, I should add target_include_directories(A PUBLIC .) to A/CMakeLists.txt, but that does not work. What am I missing here?
For completion's sake, here's the dumbed-down CMake files:
cmake_minimum_required (VERSION 3.5.1)
project(main C CXX)
add_subdirectory(A)
add_subdirectory(B)
A/CMakeLists.txt
cmake_minimum_required (VERSION 3.5.1)
add_library(A SHARED "")
target_include_directories(A PUBLIC .)
target_sources(A PUBLIC ...)
B/CMakeLists.txt
cmake_minimum_required (VERSION 3.5.1)
add_library(B SHARED "")
target_link_libraries(B A)
target_sources(B PUBLIC ...)
The error I get is the following
CMake Error at B/CMakeLists.txt:3 (add_library):
Cannot find source file:
Access.hpp
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp .hxx .in .txx
I'm following this tutorial, explaining about target_link_libraries and target_include_directories.
Don't use target_sources(). Add source files to the add_library() command.
Or use target_sources() with PRIVATE.
Related
Let's say I have two sub-projects: A and B
This is my root CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project ("Project")
add_subdirectory ("A")
add_subdirectory ("B")
In /B I have file test.h
How can I include /B/test.h in A ?
I have tried to add target_include_directories(B) in /A/CMakeLists.txt but it does not seem to work
When you write add_subdirectory(B) (quotes are not necessary), you must have a CMakeLists.txt in the directory B.
This CMakeLists.txt may have the following content:
add_library(targetB INTERFACE)
target_include_directories(targetB INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
These 2 lines create a CMake target called targetB with the INTERFACE property. This is very handy for header only library. All cmake target that links with targetB will then include the CMAKE_CURRENT_SOURCE_DIR with is the directory A where your test.h is.
Then, you have add_subdirectory(A) with a CMakeLists.txt that may look like this (assuming you have a main in this dir A):
add_executable(foo ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
target_link_libraries(foo PRIVATE targetB)
Then second line create the relation between the target foo and the target targetB and, when compiling, the path to your test.h will be set in the command line.
This question already has answers here:
What's the CMake syntax to set and use variables?
(3 answers)
Closed 2 years ago.
here is my code of cmake :
PROJECT (HELLO)
SET(SRC ./main.c)
MESSAGE(STATUS "This is BINARY dir "${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir"${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello SRC)
if I run, what appears in front of me is that:
-- Configuring done
CMake Error at CMakeLists.txt:5 (ADD_EXECUTABLE):
Cannot find source file:
SRC
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
CMake Error: CMake can not determine linker language for target: hello
CMake Error: Cannot determine link language for target "hello".
-- Generating done
if I change my code to
PROJECT (HELLO)
SET(SRC ./main.c)
MESSAGE(STATUS "This is BINARY dir "${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir"${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ./main.c)
it just works well.
So, what happens to SET? why didn't it work well?
You need to use:
ADD_EXECUTABLE(hello ${SRC})
Otherwise, cmake just thinks you have a source file named "SRC" leading to that error you see.
My directory structure of project is build with multi CMakeLists.txts.
root
CMakeLists.txt
Src
main.c
CMSIS_lib
calculate.c
calculate.h
CMakeLists.txt
cmake
toolchain.cmake
build
In my CMSIS_lib I build separately my dependency source files calculate.c
and calculate.h with CMSIS_lib/CMakeList.txt:
set(util_source_files
calculate.c
calculate.h
)
add_library(util ${util_source_files})
target_include_directories(util calculate.h)
In my root CMakeLists.txt:
cmake_minimum_required(VERSION 3.4)
project(main_projct)
set(TOOLCHAIN_PREFIX /opt/gcc-arm-none-eabi)
set(CMAKE_TOOLCHAIN_FILE cmake/toolchain.cmake)
add_subdirectory(CMSIS_lib)
add_executable(main_projct main.c)
target_link_libraries(main_projct util)
Problem is that I must tell my compiler to add a #define GUCCI in my calculate.h (In MakeFile I know there is flag to tell a header define with -DGUCCI). I would like to add this flag to my compiler in my CMSIS_lib/CMakeList.txt, because when the first CMSIS_lib/CMakeList.txt is done building, he will skip everything under #ifndef GUCCI in my calculate.h, and when added in root CMakeLists.txt with target_link_libraries() I will not have all defines configuration correctly.
I am using cross-compiler and in my toolchain.cmake I use to define compiler flags with command SET_TARGET_PROPERTIES(${TARGET} PROPERTIES COMPILE_DEFINITIONS GUCCI}"), but this is to late because this only is seen by my root CMakeLists.txt and not by my sub director CMakeLists.txt.
Your CMSIS_lib/CMakeLists.txt should look like this:
set(util_source_files
calculate.c
calculate.h
)
add_library(util ${util_source_files})
target_include_directories(util ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(util PUBLIC GUCCI)
Note target_compile_definitions line, with PUBLIC parameter: it instructs cmake to use -DGUCCI compiler option while compiling util, and all targets that are linked against util.
Also note change in target_include_directories. You placed header file as parameter, but you should place directory instead.
I have the jpeglib library, built with cmake and visual studio 2005. And I also have a separate program that uses this library. How can I compile that program so that I can debug both program and library code?
My first attempt was by just including the main program's project into the libjpeg solution, changing include paths and specifying the path to libjpeg .lib. This worked, but when I rerun cmake, I have to redo that. I described it here: https://board.flatassembler.net/topic.php?p=203834#203834
How can I compile those two programs using cmake itself? I tried adding this in the libjpeg CMakeList.txt :
add_executable(_main--ddraw main.cpp)
set_property(TARGET _main--ddraw PROPERTY RUNTIME_OUTPUT_DIRECTORY "c:/_src/_main--ddraw3")
target_link_libraries(_main--ddraw jpeg-static)
But it only resulted in this:
1>CMake Error at CMakeLists.txt:369 (add_executable):
1> Cannot find source file:
1> main.cpp
1> Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
1> .hxx .in .txx
1>CMake Error: CMake can not determine linker language for target: _main--ddraw
I have a constant MYPROJECT in my ~/.bashrc file:
export MYPROJECT = /home/loom/my_project
I can see the constant is defined in the terminal:
loom#loom$ ls -ld $MYPROJECT
drwxr-xr-x 25 loom loom 4096 Jul 21 22:12 /home/loom/my_project
I tried to use the constant in my CMakeLists.txt:
add_executable(booo src/main.cpp ${MYPROJECT}/foo/trunk/bar/File.h)
However, it produces an error:
CMake Error at CMakeLists.txt:17 (add_executable):
Cannot find source file:
/foo/trunk/bar/File.h
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
CMake Error: CMake can not determine linker language for target: booo
CMake Error: Cannot determine link language for target "booo".
It is processed without errors if I have used explicit path without $MYPROJECT:
add_executable(booo src/main.cpp /home/loom/my_project/foo/trunk/bar/File.h)
How to use path defined in .bashrc in cmake?
Instead of
add_executable(booo src/main.cpp ${MYPROJECT}/foo/trunk/bar/File.h)
use
add_executable(booo src/main.cpp $ENV{MYPROJECT}/foo/trunk/bar/File.h)
The CMake documentation states:
Use the syntax $ENV{VAR} to read environment variable VAR. See also
the set() command to set ENV{VAR}.
https://cmake.org/cmake/help/v3.4/variable/ENV.html
Turning my comment into an answer
There are a lot of ways you could do this in CMake. Out of bad experiences with using environment variables directly inside CMake projects (they have to be valid not only during the first call to CMake configuration/generation but also later during all consecutive builds), I would recommend to transfer your constant into a cached CMake variable.
I'm using one of the following ways in my projects:
Injecting MYPROJECT CMake via its -D option, e.g.
cmake -DMYPROJECT:PATH=$MYPROJECT ..
Then CMake would cache this value in its own MYPROJECT internal variable.
When you get values from the "outside" you should think about what to do if no value is provided or it's not a valid directory. Throwing a fatal error and/or retry with a default value?
The following example shows only transformation steps and sanity checks (no default value retry):
if (NOT DEFINED MYPROJECT OR NOT IS_DIRECTORY MYPROJECT)
file(TO_CMAKE_PATH "$ENV{MYPROJECT}" _ENV_MYPROJECT_REL)
get_filename_component(_ENV_MYPROJECT "${_ENV_MYPROJECT_REL}" ABSOLUTE)
if (NOT _ENV_MYPROJECT)
message(FATAL_ERROR "Environment variable MYPROJECT not provided.")
else()
set(MYPROJECT "${_ENV_MYPROJECT}" CACHE INTERNAL "")
endif()
endif()
Using find_path(), which will also cache its result:
find_path(
MYPROJECT_INCLUDE_DIR
NAMES File.h
PATHS ENV MYPROJECT
/home/loom/my_project
PATH_SUFFIXES foo/trunk/bar
)
if (NOT MYPROJECT_INCLUDE_DIR)
...
Or - assuming your external project does not only consists of header files but also libraries like foo.a - following CMake's A Sample Find Module and extending the find_path() code from above by:
find_library(
MYPROJECT_LIBRARY
NAMES foo
PATHS ENV MYPROJECT
PATH_SUFFIXES foo/lib
)
if(MYPROJECT_INCLUDE_DIR AND MYPROJECT_LIBRARY AND NOT TARGET MyProject::MyProject)
add_library(MyProject::MyProject UNKNOWN IMPORTED)
set_target_properties(
MyProject::MyProject
PROPERTIES
IMPORTED_LOCATION "${MYPROJECT_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${MYPROJECT_INCLUDE_DIR}"
)
endif()
Now you can use it directly as any other CMake target with
add_executable(booo src/main.cpp)
target_link_libraries(booo MyProject::MyProject)
More References
What's the CMake syntax to set and use variables?
preferred cmake project structure