Cmake - RicoJia/notes GitHub Wiki
========================================================================
========================================================================
-
Motivation:
- Common Linking Process:
- compile each cpp files (functions will be placeholders for linking to solve).
- Link them.
- Also, Modifications made to these files = recompilation
- Cmake maintains a tree structure compilation order, only the necessary ones will get recompiled.
- makefile is already doing that
- Cmake vs Makefile: C++ compilation is not the same across platforms, such as MS windows(VScode), Linux. CMake generates Make files cmake, across platforms
- Common Linking Process:
-
How it works
- Read CMakeList.txt, and generate files in specified locations.
- Root_dir has /build and CMakeList.txt
- cmake will generate files from the CMakeList Directory.
-
General Cautions
- Commands, function, macro names,are case insensitive. variable names are case sensitive!!
========================================================================
========================================================================
- Installation
cmake --version
- Basic workflow
cd Build #This will generate CMakeCache.txt(subsequent build of the proj) and Makefile(for building the project) #If you already have Makefile from previous builds, cmake.. can be omitted #So If you change one source file, you don't have to run cmake.. Cmake .. # Generate an executable in the build folder, USING GNU make. If you use another build system such as Ninja, do ninja make # this will put the files to the path sudo make install
- Build in Debug and Release mode
- If you don't have any external Libraries as dependencies
cmake -DCMAKE_BUILD_TYPE=Debug cmake -DCMAKE_BUILD_TYPE=RELEASE
- There will be two dirs: release and Debug
- release is faster, that's because CMake will flip the compiler flags accordingly.
- There will be two dirs: release and Debug
- Use an external Lib in Debug, Release
#step 1: download the lib binaries into two folders: /somepath/debug/libXX.so and /somepath/release/libXX.So #step 2: in you CMakeLists.txt target_link_libraries(my_app debug /somepath/debug/libXX.so release /somepath/release/libXX.So ) #step3 : run cmake -DCMAKE_BUILD_TYPE=debug or release, then the right lib will be linked. Note that you have to supply -DCMAKE_BUILD_TYPE, otherwise there will be errors.
-
make -C ANOTHER_DIR install
is to runmake install
in another directory
- If you don't have any external Libraries as dependencies
- Simplest Example
cmake_minimum_required(VERSION 3.0.0) #telling CMake project(CALCULATOR VERSION 1.0.0) add_executable(calculator main.cpp addition_lol.cpp division.cpp print_result.cpp ) #sequence of the source files do not matter, so you don't have hierarchy here.
- Adding A library locally:
add_library(math #assume the headers and src files are in the same folder. addition_lol.cpp division.cpp) target_link_libraries(calculator math print_result )
- Adding A library locally:
- Complete Example CMake 3.12 +
- top level cmake
add_subdirectory(pybind11) add_subdirectory(webserver)
- sub directory Cmake
cmake_minimum_required(VERSION 3.12) project(myproj) find_package(Poco REQUIRED COMPONENTS Net Util) #file is for getting all source files # GLOB_RECURSE is to recursively iterate thru the sub directories file (GLOB_RECURSE SRC_FILES src_1.cpp src_2.cpp) add_executable(MyEXE) #add source files target_source(MyEXE PRIVATE ${SRC_FILES}) # add include directories # {PYBIND11_INCLUDE_DIR} is added because top level cmake has included it, also it's a convention # include_directories is not for a specific target! target_include_directories(MyEXE Private ${PROJECT_SOURCE_DIR}/include ${PYBIND11_INCLUDE_DIR}) target_compile_options(MyEXE PUBLIC -Werror -Wall -Wextra) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++2a -O3") # doesn't do anything for cmake 3.1> set(CMAKE_CXX_STANDARD 14) # works for 3.1!! add_definitions(${GCC_COMPILE_FLAGS}) # we need these libraries only for the executable target_link_library(MyEXE PRIVATE Poco::Net Poco::Util)
-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14" )
has no use dunder methods
- Example with an library (main.cpp does not specify the lib name yet!)
- Directory structure
- my_lib Directory strucuture:
my_lib_dir/include/my_lib my_lib_dir/lib
- in both lib and main.cpp, use relative path: my_lib/addition.h
- root_dir CMakelist.txt
cmake_minimum_required(VERSION 3.0.0) #telling CMake project(CALCULATOR VERSION 1.0.0) add_subdirectory(my_lib) add_executable(calculator main.cpp ) target_link_libraries(calculator my_lib )
- in /lib
add_library(my_lib er c/addition_lol.cpp src/division.cpp src/print_result.cpp ) target_include_directories( my_lib PUBLIC include )
- my_lib Directory strucuture:
- Example: Building a shared library
- crow lib
# in the lib side: INCLUDE_DIRECTORIES("${BOOST_DIR}/include") LINK_DIRECTORIES("${BOOST_DIR}/lib") #if you have lib.a ... ... All the libs util depend on! #if you have other unbuilt lib targets, you can do add_library as well, # Storing these cache variables is a convention for parent projects to use set(WEBSERVER_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE INTERNAL "") set(WEBSERVER_LIBRARIES ${PYTHON_LIBRARIES} CACHE INTERNAL "") # in the application side: INCLUDE_DIRECTORIES("${BOOST_DIR}/include") LINK_DIRECTORIES("${BOOST_DIR}/lib") add_executable(webserver_helloworld webserver_helloworld.cpp) add_dependencies(webserver_helloworld util) #THIS IS GOLDEN, cmake enforces libutil.a to be built in the corresponding $CMAKE_BINARY_DIR. If you have one thread, I guess it's fine, but if you have multiple threads, this saves lives. # header only lib uses interface, which will propagate the usage requirement # header only lib doesn't have build_specifications cuz it doesn't need to be built #This just links the library, doesn't enforce the the lib to be built successfully before we link target_link_libraries(webserver_helloworld INTERFACE "${UTIL_LIB}" "${CMAKE_THREAD_LIBS_INIT}")
- Caution:
-
static libs do not carry info about its dependencies.
- Say A links B as private, A is built as a static lib, and C links A, then C needs B added to the linker command.
- solution: You need to do
INCLUDE_DIRECTORIES
,LINK_DIRECTORIES
in both the lib and the target -
Also, need to add
target_link_libraries(target_name -ljpeg)
FOR ALL static libs in every user of util.- the error message is not suggestive of where the probablem was: Experience: check the downstream applications if they have linked the libs! An error looks like:
../../util/libutil.a(util_decoder.cpp.o): In function `Jpeg_Compressor_t::write_JPEG_file(char const*, int)': /srv/ocean/util/imaging/util/util_jpeg_compressor.h:54: undefined reference to `jpeg_std_error'
- the error message is not suggestive of where the probablem was: Experience: check the downstream applications if they have linked the libs! An error looks like:
-
static libs do not carry info about its dependencies.
- Caution:
- Execute a command that gets run everytime (in this case proto generation)
add_custom_command ( OUTPUT dummy_output WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/some_dir COMMAND bash -c "python -m grpc_tools.protoc -I . --python_out=. --pyi_out=. --grpc_python_out=. YOUR_PROTO.proto" DEPENDS PATH_TO_YOUR_PROTO VERBATIM ) add_custom_target(proto_target ALL DEPENDS image_click_proto_output)
- Idea is to define a custom command in working directory, and add it to custom target so it can be run everytime.
- Another alternative is to use
execute_process
. But this method does not get run if no updates are made to theCMakeLists.txt
or not in a clean environment
========================================================================
========================================================================
- add_subdirectory(RELATIVE_PATH)
-
build
sometimes hasdebug
andrelease
- target_include_directories(name PUBLIC include)
-
include_directories
doesn't limit the scope of the include directory to the target - Lower level details
- #this automatically sets INTERFACE_INCLUDE_DIRECTORIES propertY of the lib, so in main.cpp doesn't need to worry about the path.
- build_specifications & usage_requirement
- build specification is for building the library itself
- header-only lib (interface lib) doesn't need this
- usage_requirement requires users to turn on complier, to have libs ready.. (propagate dependencies)
- PRIVATE, PUBLIC, INTERFACE
- Private: when A links B as private = A uses B in its own implementation only.
- Interface: A links B as interface = A uses B only for its public API, not for implementation (hpp counts?)
- interface library is for header only library
- just include crow in discovery_server build, hence no need to make it a static library - this will also solve issue
- Also link the boost libraries that crow needs.
- Public: combo of both.
- Caution:
-
static libs do not carry info about its dependencies.
- Say A links B as private, A is built as a static lib, and C links A, then C needs B added to the linker command.
- solution: You need to do
INCLUDE_DIRECTORIES
,LINK_DIRECTORIES
in both the lib and the target
-
static libs do not carry info about its dependencies.
- target_dependencies
-
set_target_properties
check how to build that. -
target_link_libraries(calculator PRIVATE math)
- PRIVATEhere prevents libs to be accessible to other libs.
- If A depends on B, B depends on C:
target_link_libraries(B PUBLIC C) target_link_libraries(A PUBLIC B)
-
- add_dependencies(webserver_helloworld util)
- THIS IS GOLDEN, cmake enforces libutil.a to be built in the corresponding $CMAKE_BINARY_DIR. If you have one thread, I guess it's fine, but if you have multiple threads, this saves lives.
- can be used to make sure only one lib is built.
- add_executable
- you can have more than 1 executables
- Build a lib if you want to share with others
- Make a lib
add_library(NAME src) target_include_directories(name PUBLIC include)
- imported lib (ref)
- Perks:
- the parent project just needs to find it, no need to compile it.
- parent project just needs to link the library, no need to include the /include -Because the INTERFACE property has indicated where the include dir is
- Create lib that can be imported
# Static means static library # IMPORTED means no dependencies are needed add_library(Abc STATIC IMPORTED) # a convention: use namespace add_library(boost::asio static IMPORTED) # we need to specify imported location, for debug and release mode set_target_properties(boost::asio PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/asio/asio.lib" )
- Use imported lib
find_package(spdlog REQUIRED) add_executable(MyEXE) target_source(MyExe "main.cpp") target_link_libraries(MyExe SPDLog::spdlog) #no need to do target_include_directories!
- Perks:
========================================================================
========================================================================
- Execute a bash Commands
execute_process(COMMAND "echo "holi"")
- make a copy with a different name:
add_custom_command(TARGET PUBLIC example POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/example.cpython* ${CMAKE_BINARY_DIR}/example.so)
-
set_target_properties(new_thing PROPERTIES SUFFIX ".so.1")
change suffix of the object - Change compile flags:
- this is appending to the existing flags.
set_source_files_properties( ${list_of_your_files} PROPERTIES COMPILE_FLAGS "-Wall" )
- to unset and set:
#TODO UNSET(GCC_COMPILE_FLAGS) #TODO SET(GCC_COMPILE_FLAGS "-Wall") #TODO
-
target_compile_options()
will change the compile options, but some flags may not be grouped into compile_options!-
COMPILE_DEFINITIONS
do not haveGCC_COMPILE_FLAGS
. SoGCC_COMPILE_FLAGS
is still in a set of flags.
-
- make verbose=1 may not show flags
-
add_definition(GCC_COMPILE_FLAGS)
actually add GCC_COMPILE_FLAGS.set(GCC_COMPILE_FLAGS)
simply sets the variable, but not effective. Also,add_definition
works for sub_directory as well.- remove definition is effective, where?
- this is appending to the existing flags.
========================================================================
========================================================================
- Basics
- you can store some variables in
CMakeCache.txt
- Use cache variable as kind of a "default value", there are 500+ cache variables!!
- CMake will first find the locally defined variable, then the global scoped variables.
- cache variables are global
- Usage
set(A "123" CACHED STRING "This is a comment")
message(CACHED ${A})
message(${A}) # will return 123
set(A "000")
message(${a}) #will return 000 as local variables will be taken first.
-
Important usage: Set compiler flags, and pass as #define into main.
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -DRICO_OPTION") #Note, CMAKE_C_FLAGS may not work. add_definitions(-DRICO_OPTION"="${CMAKE_SOURCE_DIR}") #Might work too, needs verification // main.cpp int main(){ #ifdef RICO_OPTION //use ```#ifndef``` if something is not defined. #endif }
- if you have C and C++ at the same place:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3 -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -O3 -fPIC")
- modify a cache variable: you may use this when first installing something
set(A "123" CACHED STRING "COMMENTS") #this will be run only during the first time cmake is run. Afterwards, the CMakeCache.txt has been created, so no set commands can change the cache variable
set(A "lol" CACHED STRING "COMMENTS") #This is not gonna change anything.
set(A "lol" CACHED STRING "COMMENTS" FORCE) # This will change the cache variable (in CMakeCache), but this is not recommended,because the user may not be aware of it. when using -D
- or use -D (the recommended way)
cmake -Dname=hcharile ..
- Common cache variables
- CMake_SOURCE_DIR vs PROJECT_SOURCE_DIR
- CMake_SOURCE_DIR refers to the outer most CMakeList.txt for the call, PROJECT_SOURCE_DIR refers to the closes file that has project() to the current CMakeList.txt
- Use
PROJECT_SOURCE_DIR
, becauseCMake_SOURCE_DIR
depends on where you call CMakeList.txt
- Other common variable
CMAKE_VERSION
CMAKE_MAJOR_VERSION #3
CMAKE_MINOR_VERSION #0
CMAKE_PATCH_VERSION #2
CMAKE_PROJECT_NAME #Name of the top level project
PROJECT_NAME #name of the current level project (like a lib name)
CMAKE_GENERATOR #GNU Make, Ninja, etc. you can also use cmake -G... to do the same thing.
CMAKE_CURRENT_SOURCE_DIR #the directory of the CMakeList.txt
CMAKE_INSTALL_PREFIX #/usr/local
- Compiler Flags
-
CMAKE_CXX_FLAGS
is set by CMake during OS and toolchain detection. This is a cached variable - Common compiler flags
-
fPic
: position independent code (PIC), aka position-independent executable (PIE), means generated machine code is not dependent on being located at a specific location.- Basics
- each program has its own address space. Shared Lib can use PIC, so it can execute properly without absolute address
- Contrary to Absolute code (must be loaded at a specific location)
- Uses relative addressing, whcih is slightly slower, and bigger as well
- In the old times, code are non-PIC. So the address space of two different shared libs might be the same.
- Your GCC should compile with fpic by default now
- some good reads
-
fPIE
is for executables- use
fPIE
only if being used on executable, or a static library that will eventually linked to position-independent executable - use
fPIC
only if making a static library
- use
- Basics
-
- Warnings (https://www.foonathan.net/2018/10/cmake-warnings/)
-
-Werror
: treat warnings as errors
-
- Environment variable
- also has global scopes, but not stored in cache files
- Use
set (ENV var value) $ENV{var}
========================================================================
========================================================================
- Basics
- a module can be seen as a part of a CMakeList.txt, that can be reused.
- a module has .cmake. CMakeList.txt is a "List File"
- Use a system module: in default location
/usr/local/share/..?
- Make our own module - File structure:
module - CMakeList.txt - my_module.Cmake - build- CMakeList.txt
Cmake cmake_minimum_required(3.0.2) project(my_calc) list(APPEND CMAKE_MODULE_PATH ) #MUST specify path include(my_module)- my_module.Cmake, **Does not create another function scope!**
message("Hola") # this module is just another part of CMakelist.txt ```
- Download, Compile, Install (install is in usr)
- Install is to copy items to the default location /usr/local/include/(h) and /usr/local/lib/ (src), so other ppl can find it.
- verify by
message(${CMAKE_INSTALL_PREFIX})
, you will see /usr/local - 2 options
#1. using the files option, to copy the my_math_addition file to the destination install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/my_math addition.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/my_math)``` # Or assume you have my_math built, as a target using add_library install(TARGETS my_math DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/my_math)
- verify by
- e.g, Install a package that could be included by other packages
```CMake
#create my_export-config.cmake files
install(TARGETS my_math EXPORT my_export DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/my_math)
# put my_export-config.cmake in the designated path. The FILE option renames my_export-config.cmake
install(EXPORT my_export FILE my_math-config.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/my_math)
target_include_directories(my_math PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
```
- Set Generator Expressions to change ```INTERFACE_INCLUDE_DIRECTORIES``` otherwise, when we do ```target_include_directories(my_math PUBLIC include)```, this property will be ```/home/.../ the whole path``` . So you replace it with
2. Build and install the project
- build_essentials include gcc and g++
- ```make -j7``` means run make on 7 threads, but this might fail sometimes.
- ```make VERBOSE=1``` will give you a full list of files included.
- If you can't find ```.h file```, try to download -dev or -devel package
- make install for makefile in a differnt directory ```make -C DIRECTORY install```
3. Find_Package
```Cmake
find_package(ABC) #find ABC-config.cmake in /usr/local/lib/ABC (1 of many), also, ABC_FOUND is set here!
if (ABC_FOUND)
#do stuff
else()
message(FATAL_ERROR "my math not found")
endif()
```
- find_package has 2 modes
1. ```find_package(ABC CONFIG)``` is the config mode, which searches for ```ABC-config.cmake```, This is kept in ```/usr/local```
- E.g,
```Cmake
Find_Package (OpenCV REQUIRED) #1. becareful with cases, since cmake will search for OpenCVConfig.cmake;
# REQUIRED will make CMake throw an error if not found, else it's treated as an optional package.
# there are no .so or .a files explicitly
#so you need to find them using these paths by convetion:
#libraries: XYZ_LIBRARIES / XYZ_LIBS
#inlude Dir: XYZ_INCLUDES / XYZ_INCLUDE_DIR
#find /usr -name *opencv*cmake
add_executable(DisplayImage main.cpp)
target_include_directories(DisplayImage PRIVATE ${OpenCV_INCLUDE_DIRS}) #from OpenCVConfig.cmake
target_link_libraries(DisplayImage PRIVATE ${OpenCV_LIBS})
```
2. Find_Package also has a module mode, (we've been using the config mode so far, so module mode will try to find in **CMAKE_MODULE_DIR** for Findmy_math.cmake, a cache variable. )
- ```find_package(ABC MODULE)``` , which searches for ```FindABC.cmake```, this is kept in your own project
- **Saving life: If a package is not built by cmake, it still might have Find* or *config.cmake files.**
- or if it uses a software called ```pkg-config```, then we might be able to use the pkg.
========================================================================
========================================================================
- Do not use the script mode (-p empty). It doesn't allow cmake commands
message("${VAR}") does not remove ; in ${VAR}, if VAR is a list message(${VAR}) does remove ; and white spaces
- A list is a ; separated string
- Variables - all variables are of string type. You can dereference by ${VAR}
set (Name Bob Smith) # This actually set Name to a list of strings: Bob; Smith. set (Name Bob; Smith) # Equivalent to the above set (Name "Bob Smith") # this gives you a single string as output
- Dereferencing a variable
set(VAR OFF) set(VAR2 VAR) VAR2 #this prints var ${VAR2} #This prints off, because ${} is Dereferencing
- String processing:
set(VAR 1 2 3 4 ...)
you can use 1-N or -1...-N (right Ato left) positions for parsing the string.- Example
set(VAR a b c;d "e;f" 2.7 "Hello there") list(APPEND VAR 1.6 XX) #will add 1.6;XX to the list list(REMOVE_AT VAR 2 -3) #will remove c, list(REMOVE_ITEM VAR a 2.7) #what is REMOVE_ITEM? removes a and 2.7 from the list! list(INSERT_ITEM 2 XX 2.7) #insert after position 2. list (REVERSE_VAR) list(REMOVE_DUPLICATES VAR) list(SORT VAR)
- every string is an item in the list, except the "Hello there" is a whole item.
- 2.7 is a separate item.
- Other utils
list(LENGTH VAR len_var) #len_var = the number of items in the list list(GET VAR 2 5 7 sublist) list(SUB_LIST 2 3 sublist2) #start at position2, length is 3. list(JOIN VAR ++ str_var) #str_var = a++b++c++d...
- Example
- Dereferencing a variable
- Basic Examples
if(<condition>) <Commands> elseif() Else endif()
- keywords for TRUE: ON, YES, TRUE, Y, a non-zero number
- keywords for FALSE: OFF, NO, FALSE, N, 0, IGNORE, NOTFOUND, "", string ending with NOT-FOUND
- Everything else will be treated as a variable, and its value will be evalutated .
- Tests
- Unary tests is to see if something exists
if (COMMAND target_link_libraries) #evaluates true if the given command is found if (DEFINED VAR) # evaluates true if VAR has been DEFINED if (EXISTS FILE_PATH)#if file exists
- Binary Tests
if (Name1 STRLESS Name2) STRGREATER STREQUAL #chars are compared one by one based on ASCII.
- Boolean: NOT, OR, AND
- Unary tests is to see if something exists
- while loop
while(NOT VAR STREQUAL "aaaaa") set(VAR ${VAR}a) endwhile()
- For-each loop
- Vanila
foreach(Name Alice Bob Chi) ... endforeach()
- in list
for_each(x IN LISTS list1 list2 list3) endforeach()
- range:
foreach(x RANGE 10) #from 0-10, all inclusive foreach(x RANGE 10 20) #from 10-20, all inclusive foreach(x RANGE 10 20 3) # step size 3.
- start and stop are all inclusive!!
- Vanila
- Basic Use
function(print_detail var) message("My name is ${var}") endfunction() print_detail(Ruotong)
- Tricky: You might need to do ${${}} for vars
fucntion(print_detail var) message(My name is ${var*}) endfunction() set (name "Ruotong") print_detail(${name})
- function scopes
- In Cmake, ALL variables outside of the function will be made a local copy inside a function. Then, the function will operate on the local copy
- Cmake functions cannot return values. work around is changing parent scope var using
PARENT_SCOPE
- E.g,
set (Name Charlie) function (print_detail) message(${Name}) #prints Charlie, because a local copy of the variable is created set(Name Bob PARENT_SCOPE) #will set parent scope endfunction()
-
add_subdirectory(dir_1 dir_2)
actually creates a separate function scope#CMakeList_Parent.txt set (Name Charlie) add_subdirectory(child_dir) # CMakeList_child.txt message(${Name}) #prints Charlie, treat this as a function scope
- What if there are more than 1 function gets defined?
fuction(print_detail var) ... #1 fuction(print_detail var) ... #2 fuction(print_detail var) ... #3 print_detail(name) #3 gets called _print_detail(name) #2 gets called __print_detail(name) #Error, you can only print the last 2 definitions of a function.
- Optional Arguments: Cmake actually has special variables for storing info about args.
Also, you can supply more than args required!
function(print_result name) message(${ARGV0}) # print Bob message(${ARGV1}) #print Alice message(${ARGV2}) #prints nothing, since we only have 2 args here message(${ARGC}) #C is for count, so 2 message(${ARGV}) #V is verbose, prints all args message(${ARGN}) #N is optional, so Alice. endfunction() print_result(Bob Alice)
- Macros
- Similar to functions, but 1. does string replacement 2.do not create a child scope, everything in parent scope
${name}) #Bob set name="Charlie" # Creating a new parent scope var message($ {name}) #Charlie is printed, since ${name} was copied and pasted as text-replacement. Parent Scope name has been changed. endmacro() print_detail(Bob) ``` - Similar to functions, but 1. does string replacement 2.do not create a child scope, everything in parent scope
========================================================================
========================================================================
-
Commenting in Cmake
#Comments #[[ MULTILINE COMMENTS #]] #uncommenting ##[[ ##]] # nested COMMENTS #[==[ This is comment line 1 comment 1 #[=[ comment 2 #]=] #]==]
-
run cmake in script mode, -p, in bash
#step 1: use which Cmake to get the cmake path. say /usr/bin/cmake #step2: chmod +x CMakeList.txt #in bash file ./CMakeList.txt #or cmake -P CmakeLists.txt
-
install a python package written in C/C++ (with make install, for installing a python package) 0. structure: from xx.yy import Binary_name
. |-- CMakeLists.txt |-- src | |-- CMakeLists.txt | |-- foo.c | `-- foo.h `-- python |-- CMakeLists.txt |-- xx -- yy | `-- __init__.py `-- setup.py.in
- setup.py.in
from distutils.core import setup, Extension import site setup(name='Binary_name', packages=['xx.yy'], version='2.0.0', package_dir={ '': '${CMAKE_CURRENT_SOURCE_DIR}' }, data_files = [(site.getsitepackages()[0] + '/xx/yy',['.so's location'])] )
- top level CMakeLists.txt link
- lower level CMakeLists is for your binary ========================================================================
========================================================================
- Undefined reference: you cannot find the function definition. So you need other cpp files.
- Your Library file cannot file header file: change
target_link_libraries
property to public or something. This can happen in make.
========================================================================
========================================================================
- Catkin build:
-
Features
- build-time cross-talk?
- No vars from other packages. Each package's build space is isolated
- Can build plain CMake packages, if they have package.xml with tag
- No need to depend on other packages for ROS messages
- All dependencies are built before the current package.
- build-time cross-talk?
-
migrating from
catkin_make
tocatkin_build
:-
find_package
was not necessary forcatkin_mane
if packages are in the same ws
-
-
Advantages
- Robust to config changes, since each pkg is isolated
- Faster, parallel
- can use
catkin clean
, instead ofrm -rf
- Can be called anywhere, not just top level
-
catkin_make --only-pkg-with-deps <target_pkg>
- build one pkg with deps
- But this will set a persistent env var, which makes future builds only build the current pkg.
- So you have to use
catkin_make -DCATKIN_WHITELIST_PACKAGES=""
to switch back -
catkin build
doesn't have such a problem
-