cmake编译
cmake_minimum_required (VERSION 2.8)
project (demo)
##第一个是生成后的名称, 后面包含所有源文件
add_executable(main main.c testFunc.c)
##cmake提供了一个命令可以把指定目录下所有的源文件存储在一个变量中
aux_source_directory(. SRC_LIST) ##将当前位置的所有源文件存储在SRC_LIST
add_executable(main ${SRC_LIST}) ##在add_executable里调用SRC_LIST
#aux_source_directory()也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件
set( SRC_LIST
.#main.c
.#testFunc1.c
.#testFunc.c)
## 在不同目录下有多个源文件 新的命令include_directories 添加多个指定头文件的搜索路径,路径之间用空格分隔
## 因为没有头文件不能通过编译 下面包含两个头文件的路径,test_func和test_func1
include_directories (test_func test_func1)
aux_source_directory (test_func SRC_LIST)
aux_source_directory (test_func1 SRC_LIST1)
add_executable (main main.c ${SRC_LIST} ${SRC_LIST1})
项目级的组织结构
<img src=“https:##gitee.com#zheshu#typora#raw#master#images#202305051703855.png” alt=“image-20230505170359824” style=“zoom:50%;” #>
cmake_minimum_required (VERSION 2.8)
project (demo)
add_subdirectory (src)
## add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
##三个参数 后面两个可选
##这个命令是 增加编译子层
source_dir 源代码目录
指定一个包含CMakeLists.txt和代码文件所在的目录,该目录可以是绝对路径,也可以是相对路径,对于后者相对路径的起点是CMAKE_CURRENT_SOURCE_DIR。此外,如果子目录再次包含的CMakeLists.txt,则将继续处理里层的CMakeLists.txt,而不是继续处理当前源代码。
binary_dir 二进制代码目录
这个目录是可选的,如果指定,cmake命令执行后的输出文件将会存放在此处
上面两个参数保证了可以和其他目录里的cmake文件一同编译,并且可以将cmake的输出放到另外一个目录里面,而第三个参数可以让新增加的子目录从ALL目录里面删除,独立于源工程
多个cmakelists例子
cmake_minimum_required (VERSION 2.8)
project (demo)
add_subdirectory (src) ##增加src编译目录
#######################################################################################
##在src目录里的CMakeLists.txt 有下面的内容
aux_source_directory (. SRC_LIST) ##将当前目录的源文件定义为SRC_LIST
include_directories (..#include) ##程序编译的时候需要头文件,而又在不同目录,因此需要将头文件包含进来
add_executable (main ${SRC_LIST})
##EXECUTABLE_OUTPUT_PATH 目标二进制可执行文件的存放位置
##PROJECT_SOURCE_DIR:工程的根目录
##这里set的意思是把存放elf文件的位置设置为工程根目录下的bin目录
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}#bin)
然后进入根目录下的build里面,然后执行cmake… 然后再make,为什么在build目录下运行cmake?cmake和make会生成很多文件,和运行没有什么关系,这样cmake的时候所有的中间文件都将在这个目录下生成,删除的时候也很好删除,非常方便,如果不这样做,cmake运行时生成的附带文件就会跟源码文件混在一起,这样会对程序的目录结构造成污染。
也可以在一个头文件中写CMakeLists.txt,下面写一个例子
使用一个cmakelists例子
# 设置cmake的最低版本和项目名称
cmake_minimum_required(VERSION 3.0)
project(mprpc)
# 生成debug版本,可以进行gdb调试
set(CMAKE_BUILD_TYPE "Debug")
# 设置项目可执行文件输出的路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}#bin)
# 设置项目库文件输出的路径 下面有关于库文件的介绍
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}#lib)
# 设置项目编译头文件搜索路径 -I
include_directories(${PROJECT_SOURCE_DIR}#src#include)
include_directories(${PROJECT_SOURCE_DIR}#example)
# 设置项目库文件搜索路径 -L
link_directories(${PROJECT_SOURCE_DIR}#lib)
# src包含了mprpc框架所有的相关代码
add_subdirectory(src)
# example包含了mprpc框架使用的示例代码
add_subdirectory(example)
动态库和静态库的编译控制
库是一组预先编译好的方法,库文件分为静态库和动态库,静态库和动态库的区别体现在程序的链接阶段。
Windows的静态库文件扩展名是 .lib,动态库文件扩展名是 .dll
Linux的静态库扩展名是 .a,动态库扩展名是 .so
无论是静态库文件还是动态库文件都是都是将函数封装编译生成.o文件然后将所有 .o 文件合并生成库文件,供自己或他人调用。好处在于编译后的库文件的源代码被加密,使用者看不到,可保密。
Linux系统存储的库的位置一般在:/lib 和 /usr/lib,库的头文件一般会被存储在 /usr/include 下或其子目录下
静态库的生成和使用
静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为.a。比如
ar -crv libhyhello.a hello.o
# 下面是将多个.o文件生成动态库
ar -crv libhyhello.a A1.o A2.o
静态库的使用
#第一种方法
gcc -o hello main.c -L. -lhyhello
#第二种方法
gcc main.c libhyhello.a -o hello
# 第三种方法
gcc -c main.c
gcc -o hello main.o libmyhello.a
动态库的生成和使用
lib开头,so结尾
gcc -shared -fPIC -o libhyhello.so hello.o
# 将所有的.o文件生成动态库
gcc -shared *.o -o libhysofile.so
动态库的使用
gcc -o hello main.c libhyhello.so
env是列出所有的环境变量,
静态库与动态库的区别
静态库会将全部进行拷贝,而动态库文件在使用的时候,只有在程序执行的时候才会被连接动态库使用
cmakelists生成库文件
cmake_minimum_required (VERSION 3.5)
project (demo)
set (SRC_LIST ${PROJECT_SOURCE_DIR}/testFunc/testFunc.c)
add_library (testFunc_shared SHARED ${SRC_LIST})
add_library (testFunc_static STATIC ${SRC_LIST})
set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc")
set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc")
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library 生成库文件,第一个参数是名字,第二个参数是SHARED或者STATIC,第三个参数是生成库的源文件。
这里使用了两次add_library一个是静态库,一个是动态库
set_target_properties是设置版本号什么的,可以看到第一个参数使用了上面的的名字,可以直接用上面的。
下面的set,LIBRARY_OUTPUT_PATH是默认库文件的输出路径,PROJECT_SOURCE_DIR是工程目录
cmakelists使用库文件
cmake_minimum_required (VERSION 3.5)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)
# find testFunc.h
include_directories (${PROJECT_SOURCE_DIR}/testFunc/inc)
find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)
add_executable (main ${SRC_LIST})
target_link_libraries (main ${TESTFUNC_LIB})
find_library 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径
target_link_libraries 把目标文件与库文件进行链接
条件编译
编译程序时想添加一些编译选项,如-Wall,-std=c++11等,就可以使用add_compile_options来进行操作。
cmake_minimum_required (VERSION 2.8)
project (demo)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_compile_options(-std=c++11 -Wall)
add_executable(main main.cpp)
一些常用的编译命令
cmake_minimum_required (VERSION 2.8) cmake的最小版本
project (demo) 项目的名称
add_executable(main main.c testFunc.c) 第一个参数是生成可执行文件的名字,由后面的参数生成
aux_source_directory(. SRC_LIST) 将当前位置的所有源文件存储在SRC_LIST变量里面
aux_source_directory (test_func SRC_LIST) 将一个源文件放入变量里面
set( SRC_LIST .#main.c .#testFunc1.c .#testFunc.c)手动将一些东西赋值给变量
add_executable(main ${SRC_LIST}) 使用后面的变量编译
include_directories (test_func test_func1) 编译的时候需要头文件,如果头文件不在当前目录下,需要指定搜索的路径
add_subdirectory (src) 项目级别,继续编译这个目录里面的cmakelists.txt
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}#bin) EXECUTABLE_OUTPUT_PATH 目标二进制可执行文件的存放位置,PROJECT_SOURCE_DIR:工程的根目录,这里set的意思是把可执行文件的位置设置为工程根目录下的bin目录
add_compile_options(-std=c++11 -Wall) 想添加一些编译选项
add_library (testFunc_shared SHARED ${SRC_LIST}) 第一个参数是名字,第二个参数是SHARED动态和STATIC静态库,第三个参数是生成库的源文件
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}#lib) 设置库文件的生成路径
find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib) find_library 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径
target_link_libraries (main ${TESTFUNC_LIB}) target_link_libraries 把目标文件与库文件进行链接
或者直接
link_directories(${PROJECT_SOURCE_DIR}#lib) 设置项目库文件搜索路径 -L
set(CMAKE_BUILD_TYPE "Debug") 生成debug版本,可以进行gdb调试