table of Contents
CMake Hello World
Compile a single source file
//main.c
#incldue<stdio.h>
int main()
{
printf("Hello World!/n");
return 0;
}
Then write a CMakeLists.txt main.c file in the same directory, as follows:
project(HELLO)
set(SRC_LIST main.c)
add_executable(hello ${SRC_LIST})
At the same time, create a build sub-folder in the same directory, used for an external compiler
into the build folder, call cmake:
$ cmake ..
$ make
After cmake will generate corresponding MakeFile, make CMakeLists.txt in accordance with certain rules are executable file hello
$ ./hello
$ Hello World!
The current directory structure:
+-- main.c
+-- CMakeLists.txt
+-- /build
+--hello
The first line of the project is very important, in general, the statement need only appear once in the whole project, the statement CMakeLists.txt directory where all of its subdirectories will be CMakeLists.txt variable PROJECT_SOURCE_DIR
values.
cmake will automatically define two variables:
PROJECT_BINARY_DIR
represents the directory project generated binary file, usually a directory cmake command execution
PROJECT_SOURCE_DIR
represents the directory where the project source files, understood as the directory where the project statement declares
By statement:
message("This is source dir: " ${PROJECT_SOURCE_DIR})
to display the default directory PROJECT_SOURCE_DIR.
set(SRC_LIST main.c)
Set SRC_LIST
value main.c
addexecutable(hello ${SRC_LIST})
from SRC_LIST
an executable file hello specified file
Second, multi-file compilation
The original split into three files main.c
//hello.h 头文件
void hello(const char * name);
//hello.c
#include<stdio.h>
#include"hello.h"
void hello(const char * name)
{
printf("Hello %s!\n",name);
}
//main.c
#include"hello.h"
int main()
{
hello("World!");
return 0;
}
CMakeLists.txt:
project(HELLO)
set(SRC_LIST main.c hello.c)
message("This is PROJECT_BINARY_DIR :" ${PROJECT_BINARY_DIR})
message("This is PROJECT_SOURCE_DIR :" ${PROJECT_SOURCE_DIR})
add_executable(hello ${SRC_LIST})
Third, generate a static library, the library link
By hello.c generate a static library libmyhello.a
modify the file as follows CMakeLists.txt
project(Hello)
set(LIB_SRC hello.c)
set(APP_SRC main.c)
add_library(myhello ${LIB_SRC})
add_executable(hello ${APP_SRC})
target_link_libraries(hello myhello)
One thing to note is that add_library(myhello ${LIB_SRC})
the resulting static library archive file name will automatically add the prefix lib , which is obtained is called libmyhello.a
a static library, and finally target_link_libraries(hello myhello)
find a static library when looking for a named libmyhello.a
file!
Fourth, the source files, libraries, header files in different folders
Now main.c hello.c hello.h under each project root directory create a folder to make it look more like a project.
At this folder are required to configure a CMakeLists.txt file for each file.
After each project directory as the source code to create folders as follows:
+-- CMakeLists.txt
+-- /src
+-- main.c
+-- CMakeLists.txt
+-- /lib
+-- hello.c
+-- hello.h
+-- CMakeLists.txt
+-- /build
CMakeLists.txt file in the root directory of the project amended as follows:
project(Hello)
cmake_minimum_required(VERSION 3.5)
message("SOURCE_DIR: " ${PROJECT_SOURCE_DIR})
set(SRC_DIR ${PROJECT_SOURCE_DIR}/src)
set(LIB_DIR ${PROJECT_SOURCE_DIR}/lib)
set(BIN_DIR ${PROJECT_SOURCE_DIR}/bin)
add_subdirectory(${SRC_DIR} ${BIN_DIR})
add_subdirectory(${LIB_DIR} lib)
The aforementioned PROJECT_SOURCE_DIR
value is the location where the project statement, so this value can be used as a global variable of the project directory.
add_subdirectory(${SRC_DIR} ${BIN_DIR})
The first parameter represents the name of the subdirectory to be added, and the second parameter indicates generated after compiling the subdirectories and files intermediate results saved location .
So SRC_LIST
the result of the compilation will be stored in the secondary directory under the root directory of the project bin
, the add_subdirectory(${LIB_DIR} lib)
said LIB_DIR
files compiled results will be saved in files under the lib directory folder execute cmake command, that is, three in the build directory lib secondary lib directory rather than the root directory of the project under
When not using the second parameter, intermediate results and files will be saved in the src and lib directory build directory.
src 中的 CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/lib)
set(APP_SRC main.c)
add_executable(hello ${APP_SRC})
target_link_libraries(hello myhello)
Because the src folder will be add to the project root directory, it ${PROJECT_SOURCE_DIR}
can be used as a global variable. It represents the header file directory for the lib file in the project root folder
lib in CMakeLists.txt
set(LIB_SRC hello.c)
add_library(myhello ${LIB_SRC})
Specify the location of the target file and library files separately
Documents/
├── bin
│ ├── ...
│ ├── hello
│ └── Makefile
├── build
│ ├── ...
│ ├── lib
│ │ ├── CMakeFiles
│ │ │ ├── ...
│ │ ├── libmyhello.a
│ │ └── Makefile
│ └── Makefile
├── CMakeLists.txt
├── lib
│ ├── CMakeLists.txt
│ ├── hello.c
│ ├── hello.h
└── src
├── CMakeLists.txt
└── main.c
According to previous compilation rules, we finally get the tree above. Documents are the root of our project, the target executable file hello saved in two directories bin, static library archive files saved in three libmyhello.a lib directory under the build in.
In order to achieve separation of the resulting compiled "cream" and the various intermediate file CMake can further specify the "essence file" save location.
lib/CMakeLists.txt
set(LIB_SRC hello.c)
add_library(myhello ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build_res/lib)
src/CMakeLists.txt:
include_directories(${PROJECT_SOURCE_DIR}/lib)
set(APP_SRC main.c)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build_res/bin)
add_executable(hello ${APP_SRC})
target_link_libraries(hello myhello)
By specify LIBRARY_OUTPUT_PATH
and EXECUTABLE_OUTPUT_PATH
, compile the make and libmyhello.a hello obtained with CMake intermediate file may be separated, are stored in the project root build_res under / bin and build_res / lib of. The CMake and intermediate files will be saved with the Makefile in the build directory.
Fifth, the use of dynamic libraries
install instructions
CMAKE_INSTALL_PREFIX
Common variables used as follows:
cmake -DCMAKE_INSTALL_PREFIX=/usr .
INSTALL(TARGETS targets... [[ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS[Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL]]
[...])
targets
Parameter is passed add_executable
and the add_library
target file name is set, the target file three types, ARCHIVE
, LIBRARY
, RUNTIME
respectively static library, dynamic library object files and executables. DESTINATION
The default path specified relative CMAKE_INSTALL_PREFIX
relative path.
install(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION libstatic
)
The above command, the target executable file myrun installed ${CMAKE_INSTALL_PREFIX}/bin
under the shared library mylib installed ${CMAKE_INSTALL_PREFIX}/lib
, install the static library mystaticlib to ${CMAKE_INSTALL_PREFIX}/libstatic
the next. If the DESTINATINO
specified path is absolute, it is CMAKE_INSTALL_PREFIX
invalid.
Such as the file is organized as follows:
t3/
├── build
├── CMakeLists.txt
├── lib
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── main.c
CMakeLists.txt top reads as follows:
project(HELLO)
cmake_minimum_required(VERSION 3.5)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/res_lib)
set(PROJ_SRC main.c)
add_subdirectory(lib)
add_executable(mainhello ${PROJ_SRC})
target_link_libraries(mainhello hello)
install(TARGETS mainhello
RUNTIME DESTINATION install_bin)
lib folder CMakeLists.txt
set(LIBHELLO_SRC hello.c)
add_library(hello SHARED ${LIBHELLO_SRC})
add_library(hello_static STATIC ${LIBHELLO_SRC})
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")
set_target_properties(hello PROPERTIES VERSION 1.2 SOVERSION 1)
install(TARGETS hello hello_static
LIBRARY DESTINATION install_lib
ARCHIVE DESTINATION install_static)
In the build in execution
cmake -DCMAKE_INSTALL_PREFIX=../ ..
make
sudo make install
-DCMAKE_INSTALL_PREFIX
The default address for the /usr/local
install instructions can be used for files, directories, scripts and so on target.
Use external shared library and header files
Previously used include_directories
commands
include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
Variable CMAKE_INCLUDE_DIRECTORIES_BEFORE
is set to ON, the include path manually added before existing priority path. There after the corresponding
link_directories
Settings need to link the path to the library
target_link_libraries(target library1 <debug | optimized> library2 ...)
to add a link libraries need to target.
find_path(myHeader NAMES hello.h PATHS /usr/inlcude /usr/include/hello)
findpath instructions for the specified folder to find the specified file and the folder where the file assigned to the corresponding variable
find_library find_path and acts like, but will find_library file path assigned to the variable, rather than the folder in the file path.
The default search path environment variable CMAKE_INCLUDE_PATH
and CMAKE_LIBRARY_PATH
specified. Both environment variables represent only cmake command in find_path and find_library default search path, it does not mean that cmake will automatically search for header files and libraries from the path. In other words, if you do not use find_ instruction, then the two environment variables is invalid.
Prior assumptions hello.h header files are installed to the folder /usr/local/include
, obtained after compiling shared libraries libhello.so libhello.so.1 libhello.so.1.2 be installed to a file folder/usr/local/install_lib
Now in order to use the shared library before compiling get, we write main.c use the library. main.c saved in the root directory of the project src t3 in
#include <hello.h>
int main.c
{
HelloFunc();
return 0;
}
t3 in CMakeLists.txt:
project(HELLOLIB)
cmake_minimum_required(VERSION 3.5)
find_path(myheader hello.h)
if(myheader)
message("myheader: " ${myheader})
# myheader 保存的是hello.h所在文件夹的路径
include_directories(${myheader})
endif(myheader)
find_library(mylibrary hello)
if(mylibrary)
# mylibrary 保存的是 hello 库文件本身的路径
# 所以不需要 link_directories
message("mylibrary: " ${mylibrary})
endif(mylibrary)
add_subdirectory(src)
src中的CMakeLists.txr
set(SRC_LIST main.c)
add_executable(mainhello ${SRC_LIST})
# mylibrary 继承自 parent CMakeLists.txt 生成的对象
target_link_libraries(mainhello ${mylibrary})
install(TARGETS mainhello RUNTIME DESTINATION install_bin)
The whole project folder structure as follows:
t3/
├── build
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.c
Enter the build directory, set environment variables, start the compilation process
# find_path 的默认路径
export CMAKE_INCLUDE_PATH=/usr/local/include
# find_lirary 的默认路径
export CMAKE_LIBRARY_PATH=/usr/local/install_lib
cmake -DCMAKE_INSTALL_PREFIX=../ ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
myheader: /usr/local/include
mylibrary: /usr/local/lib/libhello.so
-- Configuring done
-- Generating done
-- Build files have been written to: /home/hzq0/Documents/t3/build
Can be seen that myheader
the value / usr / local / include, but mylibrary
the value of/usr/local/lib/libhello.so
cmake VERBOSE=1
/usr/bin/cmake -H/home/hzq0/Documents/t3 -B/home/hzq0/Documents/t3/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/hzq0/Documents/t3/build/CMakeFiles /home/hzq0/Documents/t3/build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/hzq0/Documents/t3/build'
make -f src/CMakeFiles/mainhello.dir/build.make src/CMakeFiles/mainhello.dir/depend
make[2]: Entering directory '/home/hzq0/Documents/t3/build'
cd /home/hzq0/Documents/t3/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/hzq0/Documents/t3 /home/hzq0/Documents/t3/src /home/hzq0/Documents/t3/build /home/hzq0/Documents/t3/build/src /home/hzq0/Documents/t3/build/src/CMakeFiles/mainhello.dir/DependInfo.cmake --color=
Dependee "/home/hzq0/Documents/t3/build/src/CMakeFiles/mainhello.dir/DependInfo.cmake" is newer than depender "/home/hzq0/Documents/t3/build/src/CMakeFiles/mainhello.dir/depend.internal".
Dependee "/home/hzq0/Documents/t3/build/src/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/hzq0/Documents/t3/build/src/CMakeFiles/mainhello.dir/depend.internal".
Scanning dependencies of target mainhello
make[2]: Leaving directory '/home/hzq0/Documents/t3/build'
make -f src/CMakeFiles/mainhello.dir/build.make src/CMakeFiles/mainhello.dir/build
make[2]: Entering directory '/home/hzq0/Documents/t3/build'
[ 50%] Building C object src/CMakeFiles/mainhello.dir/main.c.o
cd /home/hzq0/Documents/t3/build/src && /usr/bin/cc -I/usr/local/include -o CMakeFiles/mainhello.dir/main.c.o -c /home/hzq0/Documents/t3/src/main.c
[100%] Linking C executable mainhello
cd /home/hzq0/Documents/t3/build/src && /usr/bin/cmake -E cmake_link_script CMakeFiles/mainhello.dir/link.txt --verbose=1
/usr/bin/cc CMakeFiles/mainhello.dir/main.c.o -o mainhello /usr/local/install_lib/libhello.so -Wl,-rpath,/usr/local/install_lib:
make[2]: Leaving directory '/home/hzq0/Documents/t3/build'
[100%] Built target mainhello
make[1]: Leaving directory '/home/hzq0/Documents/t3/build'
/usr/bin/cmake -E cmake_progress_start /home/hzq0/Documents/t3/build/CMakeFiles 0
make install
[100%] Built target mainhello
Install the project...
-- Install configuration: ""
-- Installing: /home/hzq0/Documents/t3/install_bin/mainhello
-- Set runtime path of "/home/hzq0/Documents/t3/install_bin/mainhello" to ""
note
hzq0@ceph0:~/Documents/t3/build/src$ ldd mainhello
linux-vdso.so.1 => (0x00007fffe7be6000)
libhello.so.1 => /usr/local/install_lib/libhello.so.1 (0x00007f5289427000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f528905d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5289629000)
hzq0@ceph0:~/Documents/t3/build/src$ cd ../../install_bin/
hzq0@ceph0:~/Documents/t3/install_bin$ ldd mainhello
linux-vdso.so.1 => (0x00007ffe56dfa000)
libhello.so.1 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9f91c61000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9f9202b000)
Different relocation table portion of the executable file executable object file obtained and make make install obtained. The machine needs to link the former path of the shared library is written executable file, and the latter does not . When the loader loads the latter from the system default, or the environment variable LD_LIBRARY_PATH
additional address to find dynamic link library, installed in front of the shared library that we do not install it in the default path, so that the latter can not locate the shared library at run time .