I am trying to build a project (c++ code files) that is to be applied on different type of target machines, and I am trying to include cpp files according to the machine type, for this I created options in the CMakeLists file in order to use them to whether include the cpp file or not.
option (MACHINE1 "MACHINE1 DESCRIPTION" OFF)
option (MACHINE2 "MACHINE1 DESCRIPTION" OFF)
...
...
...
add_library (SO_LIBRARY
SHARED FILE1.cpp
if (MACHINE1)
FILE2.cpp
endif ()
if (MACHINE2)
FILE3.cpp
endif ()
)
...
I already have a linked bitbake file where I can set these options on and off, it is not the problem, the issue is that CMakeFile does not accept this type of writing :
| CMake Error at CMakeLists.txt:52 (add_library):
| Cannot find source file:
|
| if
|
| Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
| .hpp .hxx .in .txx
|
|
| CMake Error at CMakeLists.txt:52 (add_library):
| No SOURCES given to target: SO_LIBRARY
is there any possible way to do it ?
Thank you very much.
cmake_minimum_required(VERSION 3.1)
option (MACHINE1 "MACHINE1 DESCRIPTION" OFF)
option (MACHINE2 "MACHINE1 DESCRIPTION" OFF)
add_library(SO_LIBRARY SHARED)
if(MACHINE1)
target_sources(SO_LIBRARY
PRIVATE
FILE2.cpp
)
endif()
if(MACHINE2)
target_sources(SO_LIBRARY
PRIVATE
FILE3.cpp
)
endif()
In modern CMake (since 3.1) you should avoid using custom variables in arguments of project commands and prefer to use target_sources
Try the following, Based on the type of the machine, assign the file name to a variable and then use it to add to sources.
if(MACHINE1)
set(SOURCEFILES "file1.cpp");
if(MACHINE2)
set(SOURCEFILES "file2.cpp");
if (MACHINE3)
set(SOURCEFILES "file3.cpp");
now add the file to add library
add_library (SO_LIBRARY
SHARED ${SOURCEFILES})
I would do something along these lines instead of option:
set(COMMON_SRC File1.cpp)
set(MACHINE1_SRC File2.cpp)
set(MACHINE1_SRC File3.cpp)
if(MACHINE1)
add_library (SO_LIBRARY SHARED ${COMMON_SRC} ${MACHINE1_SRC_SRC}
elseif(MACHINE2)
add_library (SO_LIBRARY SHARED ${COMMON_SRC} ${MACHINE2_SRC_SRC}
else()
...
endif()
Your goal is to create a list of sources which content will depend on some conditions.
Start with defining a variable and put there all common source files:
set(SOURCES
file_common_1.cpp
file_common_2.cpp
)
Then, APPEND elements to SOURCES list depending on conditions:
if(OPTION1)
list(APPEND SOURCES file_specific_machine1.cpp)
endif()
if(OPTION2)
list(APPEND SOURCES file_specific_machine2.cpp)
endif()
Finally, use SOURCES list to create a library:
add_library(SO_LIBRARY ${SOURCES})
Related
I am trying to work with CMake for the first time and am struggling to link header files into my main. My cmake directory looks like this:
Project
| CmakeLists.txt
| src
|| CMakeLists.txt
|| Main.cpp
| Libs
|| CMakeLists.txt
|| headers
|||obstacle_detection.hpp
||source
|||obstacle_detection.cpp
|build
||"build files"
I would like to link the files in the headers folder to main, but what I currently have does not appear to work. The following runs the CMake command correctly but fails to compile with the make command, being unable to find the given header file. My CMakeLists files are as follows:
Project:
cmake_minimum_required(VERSION 3.17)
project(Sensivision)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
find_package(OpenCV REQUIRED)
find_package(realsense2 REQUIRED)
find_library(darknet REQUIRED)
add_subdirectory(libs)
add_subdirectory(src)
target_link_libraries(${PROJECT_NAME} obstacle_detection)
Libs:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
src:
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
target_link_libraries(${PROJECT_NAME} ${realsense2_LIBRARY})
My include in main.cpp is
include <obstacle_detection.hpp>
I have also tried
include <headers/obstacle_detection.hpp>
and
include <obstacle_detection>
Each gives the error:
obstacle_detection.hpp: no such file or directory
What am I doing incorrectly to link the header to the main?
You haven't added any include directories to the obstacle_detection library. By listing the header file in the add_library call, this may allow the header to be displayed in an IDE, but it doesn't do anything for compilation. You should use target_include_directories to add the headers directory as an include directory for the obstacle_detection library. Otherwise, it, and other consuming targets, will have no knowledge of the headers in that directory.
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
# Add this line.
target_include_directories(obstacle_detection PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers)
# Not sure this line is necessary, as it doesn't appear you actually link anything...
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
You haven't shown the CMake code in the src directory, but be sure to link the obstacle_detection library target to the main target, e.g.:
target_link_libraries(MyExeTarget PRIVATE obstacle_detection)
In addition, because this header file is local, it is best if you use quotes to include the header:
#include "obstacle_detection.hpp"
You can use target_include_directories to add folder where your headers are located and #include <header.hpp> where needed.
Ex:
libs cmake:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_include_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
cpp:
#include <headers/obstacle_detection.hpp>
I have a C++ project containing several modules, some built as libraries, with such structure:
/MyProject
+---/build
/ModuleA
+---CMakeLists.txt <- module level CMakeLists
+---/src
| +--CMakeLists.txt <- src level CMakeLists
| +--FileA1.cpp
| +--FileA2.cpp
+---/include
| +--FileA1.h
| +--FileA2.h
| +--FileA3.h
/ModuleB
+---CMakeLists.txt
+---/src
| +--CMakeLists.txt
| +--FileB1.cpp
| +--FileB2.cpp
+---/include
| +--FileB1.h
| +--FileB2.h
| +--FileB3.h
main.cpp
CMakeLists.txt <- project level CMakeLists
CMakeLists.txt files look as follow:
project level:
cmake_minimum_required(VERSION 3.05)
project(MyProject)
subdirs(ModuleA ModuleB)
set(CMAKE_CXX_STANDARD 11)
add_executable(MyProject main.cpp)
target_link_libraries(MyProject ModuleA ModuleB)
module level:
subdirs(src)
src level:
FIND_PACKAGE(SomePackage REQUIRED)
INCLUDE_DIRECTORIES(
${SomePackage_INCLUDE_DIR}
${MyProject_SOURCE_DIR}/ModuleA/include
)
SET(SOURCE_FILES <all files from ModuleA/src goes here>)
ADD_LIBRARY(ModuleA STATIC ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(ModuleA
${SomePackage_LIBRARIES}
)
The problem is: when I include header files from 'SomePackage' in my ModuleA header files (i.e. SomePackageFile.hpp in FileA1.h) I get an error while running a build with make:
fatal error: SomePackageFile.hpp: No such file or directory
When I include them in cpp files they are visible and project compiles correctly. I assume that is sth wrong with CMakeLists on src level or entire hierarchy of files is missing something.
I have a github project to be used as a skeleton for other projects:
https://github.com/gnyiri/cmake-sandbox
If you follow this layout, you will not need to add ${SomePackage_INCLUDE_DIR} to INCLUDE_DIRECTORIES which is not the best way to add directories to the include path otherwise.
In a nutshell, you should define a new library like this:
project(module_a)
set(sources
src/source_a_1.cc
)
add_library(library_a
${sources}
)
target_include_directories(library_a
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
Then, if you define another library (library_b), you only need to add library_a in target_link_libraries:
project(module_b)
# set list of sources, needs to be extended when new source arrives
set(sources
src/source_b_1.cc
)
# define a library (static by default -> liblibrary_b.a or library_a.lib will be generated)
add_library(library_b
${sources}
)
# include directories
target_include_directories(library_b
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
# link library_b
target_link_libraries(library_b
library_a
)
Note that in this source tree, all the header files are located in
<module>/include/<module>
This way you will include a header file from like this:
#include "<module>/<module_header.h>"
This is simply because /include will be on include path.
Switching from INCLUDE_DIRECTORIES() to TARGET_INCLUDE_DIRECTORIES() was the case, no change to the structure of the project was needed.
If I have .h and .cpp files in the directory src, where the .cpp files include the .h files, using these commands in CMake:
aux_source_directory(src SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
And opening that CMake file in Qt Creator, gets all the files (sources + headers) in the list of project files (the file tree on the left by default).
Now, on the other hand, if I put all the .h files in a directory include, and use this:
include_directories(include)
aux_source_directory(src SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
The header files disappear from the project files!
How can I keep the header files in that directory, and still have them listed in Qt Creator's project files?
You shouldn't use aux_source_directory() for your task. That command is for something different. Just list the source files (or put them in a variable).
You shouldn't use include_directory() for defining include directories any more. This command will just populate the -I flag of the compiler. Define a variable with the header files and add that to the executable.
In case you don't want to list every file manually, use file(GLOB ...). But be aware of the caveats mentioned frequently all over the web with using that command.
Afterwards, tell CMake to populate the -I flag only for that executable with the include directory. That way, other targets don't get polluted by includes, they shouldn't use.
set(SOURCES
src/main.cpp
src/whatever.cpp)
set(HEADERS
include/whatever.h)
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC include)
I add my header files always explicit to avoid any surprise.
But on MacOS using QtCreator 4.2.0 and cmake 3.7.1 I can't reproduce your issue.
However I recommend to use following structure to know which files are within project and to trigger update of cmake's data during update of CMakeLists.txt.
In project/CMakeLists.txt:
add_subdirectory(src)
include_directory(include)
add_executable(foo ${SRC_LIST})
In project/src/CMakeLists.txt:
set(SRC_LIST
${SRC_LIST}
${CMAKE_CURRENT_SOURCE_DIR}/a.cpp
${CMAKE_CURRENT_SOURCE_DIR}/b.cpp
PARENT_SCOPE
)
I'm trying to use GLOB_RECURSE to specify my sources and headers files. Currently, my CMakeLists.txt for a static library is:
project(LinearSystemLib)
file(GLOB_RECURSE ${PROJECT_NAME}_headers ${PROJECT_SOURCE_DIR}/*.h)
file(GLOB_RECURSE ${PROJECT_NAME}_sources ${PROJECT_SOURCE_DIR}/*.cpp)
add_library(
${PROJECT_NAME} STATIC ${${PROJECT_NAME}_headers}
${${PROJECT_NAME}_sources}
)
install(
TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION libs
ARCHIVE DESTINATION archives
)
The library directory looks like this:
LinearSystemLib
CMakeLists.txt
source
LinearSystemLib.cpp
include
LinearSystemLib.h
When I run command cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug (in the build directory) everything goes ok. Yet, command make it displays the following:
/home/felipe/Documents/Dados/SINMEC/Eclipse/LinearSystemLib/source/LinearSystemLib.cpp:1:29: fatal error: LinearSystemLib.h: No such file or directory
Is my CMakeLists wrong? I don't want to set specify the sources and headers files by name. I'm not finding information about glob_recurse easily.
I can make it work by listing the sources and headers files by name. However, it MUST be done with the glob_recurse or with glob.
I solved my problem, here's what LinearSystemLib directory looks like:
LinearSystemLib
CMakeLists.txt
source
LinearSystemLib.cpp
include
LinearSystemLib.h
The CMakeLists.txt contains:
project(LinearSystemLib)
#INCLUDE DIRECTORIES
include_directories(${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/include)
#SEARCH FOR .CPP AND .H FILES
file(GLOB ${PROJECT_NAME}_headers ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/include/*.h)
file(GLOB ${PROJECT_NAME}_sources ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/source/*.cpp)
#ADD LIBRARY
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_sources})
#DEFINE OUTPUT LOCATION
install(
TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION static_libs
)
You don't actually NEED to add the .h/.hpp files using GLOB. I did it because otherwise, Visual Studio (or CodeBlocks) wouldn't create a "Header Files" folder on the project menu.
I wasn't properly specifying the path where GLOB would find the files.
${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/source/
You need to add
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
so the correct -I argument is added to your compilation step. Use make VERBOSE=1 to see exactly what commands make is executing.
I have the following folder hieararchy in my QT project and I need to use some classes of the Utility folder in the classes of the ImageProcessing folder.
CMAKE file of Utilities:
file(GLOB Utilities_Files *.cpp *.h *.hpp)
# add component
add_library(Utilities ${Utilities_Files})
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(Utilities ${OpenCV_LIBRARIES})
CMAKE file of ImageProcessing:
file(GLOB ImageProcessing_FILES *.cpp *.h *.hpp)
# add component
add_library(ImageProcessing ${ImageProcessing_FILES})
include_directories(../Utilities)
target_link_libraries(ImageProcessing Utilities)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(ImageProcessing ${OpenCV_LIBRARIES})
when I try to include classes from Utilities in classes of ImageProcessing:
#include "Utilities/className.h"
The compiler always fails.. Not sure why? It seems there is something missed or misunderstood.
Thanks.
Your line include_directories(../Utilities) adds the path ../Utilities to include directories. However, you include Utilities/className.h in the source file which makes the compiler search for files ./Utilities/className.h and ../Utilities/Utilities/className.h.
Remove one of the Utilities in either include_directories or #include.
include_directories(..)
or
#include "className.h"