Cmake 之Linux库编译

发布时间:2024年01月20日

一 camake第一列,C编译为so库

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

对应的CmakeList文件

cmake_minimum_required(VERSION 3.27)
project(test C)

set(CMAKE_C_STANDARD 11)

add_executable(test main.c)

二 Cmake介绍

2.1?CMake 是一个跨平台的项目构建工具,CMake可以生成各种构建系统的配置文件,包括Makefile、Visual Studio项目文件、Xcode项目文件等,可以帮助开发人员简化项目的构建过程,提高开发效率

2.2?CMake执行流程图

2.3 Cmake最简单且必须的3个文件,如开头那个CmakeLists.txt

  • cmake_minimum_required:
  • 指定使用的 cmake 的最低版本
  • 可选,非必须,如果不加可能会有警告
cmake_minimum_required(VERSION 3.0)
  • project:
  • 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言)
  • 如果不需要这些都是可以忽略的,只需要指定出工程名字即可
project(<PROJECT-NAME> [<language-name>...])

#或

project(<PROJECT-NAME>
       [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
       [DESCRIPTION <project-description-string>]
       [HOMEPAGE_URL <url-string>]
       [LANGUAGES <language-name>...])
  • ?add_executable:
  • 定义工程会生成一个可执行程序,add_executable(可执行程序名 源文件名称)
  • 源文件名可以是一个也可以是多个,如有多个可用空格或;间隔
# 方式1
add_executable(app add.c div.c main.c mult.c sub.c)
# 方式2
add_executable(app add.c;div.c;main.c;mult.c;sub.c)

三 执行Cmake命令编译C/C++文件

3.1 安装Cmake,最新版

sudo apt install cmake

安装失败错误解决:

E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?

解决:需要更新apt

$ apt-get update
Reading package lists... Done

E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
解决:无权限,切换root用户

$ su root
Password:
su: Authentication failure

解决:设置root密码

$ sudo passwd root
New password:
Retype new password:
passwd: password updated successfully
再次安装Cmake


# sudo apt install cmake
Reading package lists... Done

3.2 创建项目文件夹,里面包含C文件和CMakeLists.txt?

cmaketest
├── test1.c
├── test2.c
├── main.c
├── CMakeLists.txt

test.h

#ifndef HEAD_H
#define HEAD_H

int add(int a ,int b);
int sub(int a ,int b);
int mult(int a ,int b);
int div(int a ,int b);

#endif

test1.c

#include "test.h"

int add(int a ,int b){
	return a+b;
}

int sub(int a ,int b){
	return a-b;
}

test2.c

#include "test.h"

int mult(int a ,int b){
	return a*b;
}

int div(int a ,int b){
	return a/b;
}

mian.c

#include <stdio.h>
#include "test.h"


int main(){
	
	int a=20;
	int b=10;
	
	int value1 = add(a,b);
	int value2 = sub(a,b);
	int value3 = mult(a,b);
	int value4 = div(a,b);
	
	printf("a , b is%d,%d\n", a, b);
    printf("a + b = %d\n", value1);
    printf("a - b = %d\n", value2);
    printf("a * b = %d\n", value3);
    printf("a / b = %d\n", value4);

	
	return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(cmaketest)
add_executable(app test1.c test2.c main.c)

3.3 进入项目目录,执行cmake命令,cmaketest

# cd /mnt/d/VSProject/cmaketest

执行cmake,注意要加.,表示当前目录

# cmake .

可能会报错

root@LAPTOP-G67LH5N6:/mnt/d/VSProject/cmaketest# cmake .
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is unknown
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
CMake Error at CMakeLists.txt:2 (project):
? No CMAKE_CXX_COMPILER could be found.

? Tell CMake where to find the compiler by setting either the environment
? variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
? to the compiler, or to the compiler name if it is in the PATH.

需要安装C++编译器:

sudo apt-get install build-essential

再次执行cmake命令,可以看到这次成功了

root@LAPTOP-G67LH5N6:/mnt/d/VSProject/cmaketest# cmake .
-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/d/VSProject/cmaketest?

此时项目目录会增加一些makefile相关文件

maketest
├── CMakeCache.txt? ? ? ? ? ?# new add file
├── CMakeFiles? ? ? ? ? ? ? ? ? # new add dir
├── cmake_install.cmake ? ?# new add file
├── CMakeLists.txt
├── Makefile? ? ? ? ? ? ? ? ? ? ? ? # new add file
├── test1.c

├── test2.c
└── main.c

?3.4 执行make命令?

# make

?编译成功会出现以下信息:

# make
[ 25%] Building C object CMakeFiles/app.dir/test1.c.o
[ 50%] Building C object CMakeFiles/app.dir/test2.c.o
[ 75%] Building C object CMakeFiles/app.dir/main.c.o
[100%] Linking C executable app
[100%] Built target app

此时的文件目录

cmaketest
├── app? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 生成的可执行程序
├── CMakeCache.txt? ? ? ? ?# CMake缓存
├── CMakeFiles? ? ? ? ? ? ? ? ?# app.dir里面是生成的so库
├── cmake_install.cmake
├── CMakeLists.txt
├── main.c
├── Makefile
├── test.h
├── test1.c
└── test2.c

3.5 注意,必须写入口文件,mian方法入口 ,否则可能出现以下错误

# make
[ 25%] Building C object CMakeFiles/app.dir/test1.c.o
[ 50%] Building C object CMakeFiles/app.dir/test2.c.o
[ 75%] Building C object CMakeFiles/app.dir/main.c.o
[100%] Linking C executable app
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x1b): undefined reference to `main'

collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/app.dir/build.make:129: app] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/app.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

3.6 注意,mian.c里面最好引用头部文件,可以避免被多次包含

#ifndef HEAD_H
#define HEAD_H

……(头文件内容)

#endif

否则可能在编译的时候出现以下错误,意思出现多次方法加载,重复加载

# make
[ 25%] Building C object CMakeFiles/app.dir/test1.c.o
[ 50%] Building C object CMakeFiles/app.dir/test2.c.o
[ 75%] Building C object CMakeFiles/app.dir/main.c.o
[100%] Linking C executable app
/usr/bin/ld: CMakeFiles/app.dir/main.c.o: in function `add':
main.c:(.text+0x0): multiple definition of `add'; CMakeFiles/app.dir/test1.c.o:test1.c:
(.text+0x0): first defined here
/usr/bin/ld: CMakeFiles/app.dir/main.c.o: in function `sub':
main.c:(.text+0x18): multiple definition of `sub'; CMakeFiles/app.dir/test1.c.o:test1.c:(.text+0x18): first defined here
/usr/bin/ld: CMakeFiles/app.dir/main.c.o: in function `mult':
main.c:(.text+0x2e): multiple definition of `mult'; CMakeFiles/app.dir/test2.c.o:test2.c:(.text+0x0): first defined here
/usr/bin/ld: CMakeFiles/app.dir/main.c.o: in function `div':
main.c:(.text+0x45): multiple definition of `div'; CMakeFiles/app.dir/test2.c.o:test2.c:(.text+0x17): first defined here
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x1b): undefined reference to `main'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/app.dir/build.make:129: app] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/app.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

3.7 上面都在同一个文件夹,看着乱,我们可以新建一个文件夹,来放编译生成的目录。

cmake 用两个..,来切换到源码目录编译

# mkdir build
# cd build
# cmake ..

-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/d/VSProject/cmaketest/build

这时我们的目录就简洁了很多

cmaketest

├── CMakeLists.txt
├── main.c
├── test.h
├── test1.c
├── test2.c
├── build? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # cmake,make后生成的文件夹
├──├── app? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # 生成的可执行程序
├──├── CMakeCache.txt? ? ? ? ?# CMake缓存
├──├── CMakeFiles? ? ? ? ? ? ? ? ?# app.dir里面是生成的so库
├──├── cmake_install.cmake
├── ├──Makefile

四 Cmake配置参数

4.1 定义变量:SET指令

# NAME :变量名
# VALUE:变量值

SET(NAME VALUE)

?这样我们就可以把上面的那些源文件放在一个SRC_LIST变量中

# 各个源文件之间使用空格间隔,有可用分号隔开
# SRC_LIST 是源文件存储的变量名
set(SRC_LIST test1.c  test2.c   main.c)

add_executable(app  ${SRC_LIST})

4.2? 其它常用变量

指定C++标准,如通过C++标准对应的宏DCMAKE_CXX_STANDARD,指定C++标准为C++11

shell语法
$ g++ *.cpp -std=c++11 -o app

cmake语法
set(CMAKE_CXX_STANDARD 11)

指定输出路径,宏?EXECUTABLE_OUTPUT_PATH

# 定义一个变量用于存储一个绝对路径
# 从根目录开始完整路径-可执行程序目录
set(MYPATH /mnt/d/VSProject/cmaketest/outpath)

#?将拼接好的路径值设置给宏
set(EXECUTABLE_OUTPUT_PATH ${MYPATH}/bin)

搜索文件:aux_source_directory命令

# 上面只是简单配置,生成可执行程序。但只适用于文件少的情况,文件上百个就不合适了,所以需要通过搜# 索文件配置来简化和提高执行效率。

# dir:要搜索的目录
# variable:将从dir目录下搜索到的源文件列表存储到该变量中
aux_source_directory(dir variable)


# 示例:
# 设置源文件路径变量SOURCE_DIR 
set(SOURCE_DIR /mnt/d/VSProject/cmaketest)
# 搜索 src 目录下的源文件
aux_source_directory(${SOURCE_DIR}/src SRC_LIST)
# 添加程序编译
add_executable(app  ${SRC_LIST})

?搜索文件:file命令

#?GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
#?GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中
# name:变量名
# path:源文件路径
file(GLOB/GLOB_RECURSE name path);



# 示例:
set(SOURCE_DIR /mnt/d/VSProject/cmakeList)

file(GLOB MAIN_SRC ${SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${SOURCE_DIR}/include/*.h)

包含头文件:include_directories命令

#?path头文件目录
include_directories(path)

#?示例
set(SOURCE_DIR /mnt/d/VSProject/cmakeList)
include_directories(${SOURCE_DIR}/include)

4.3上面提到的set用法完整示例

# 最小cmake版本
cmake_minimum_required(VERSION 3.0)
# 项目名字
project(cmaketest)
# C++标准
set(CMAKE_CXX_STANDARD 11)
# 定义输出路径
set(MYPATH /mnt/d/VSProject/cmaketest/outpath)
# 输出路径
set(EXECUTABLE_OUTPUT_PATH ${MYPATH}/bin/)
# 设置源文件路径变量
set(SOURCE_DIR /mnt/d/VSProject/cmaketest)
# 搜索头文件目录
include_directories(${SOURCE_DIR}/include)
# 搜索源文件目录
file(GLOB SRC_LIST ${SOURCE_DIR}/src/*.c)
# 添加执行目录
add_executable(app  ${SRC_LIST})

执行命令,则会生成上面目录的文件

# mkdir build
# cd build
# cmake ..
?

# make

文件目录
cmaketest
├── build
├── CMakeLists.txt
├── include
│???└── test.h
└── src
? ? ├── test1.c
? ? ├── test2.
? ? └── main.cpp?

五?编译静态,动态库

5.1 前面操作都是生成的可执行程序,把可执行程序进行安装打包,可以生成Linux的安装包程序。但如果我们想要生成三方库供其它平台使用,就要编译成静态(.a),或者动态(.so)库文件

5.2 生成三方库只需要在上面CMakeLists.txt基础上增加下面指令就可以:

把?add_executable (执行程序命令)换为 add_library(库命令)

#?库名称,自定义就可以,如mylib
#?库类型,STATIC(静态)/ SHARED?(动态)
#?源文件,一个或多个,
add_library(库名称? 库类型? 源文件1 [源文件2] ...)?


# 示例
cmake_minimum_required(VERSION 3.0)
project(cmaketest)
set(SOURCE_DIR /mnt/d/VSProject/cmaketest)
include_directories(${SOURCE_DIR}/include)
file(GLOB SRC_LIST "${SOURCE_DIR}/src/*.c")
add_library(calc STATIC ${SRC_LIST})

5.3 输出目录要注意下,根上面不同

EXECUTABLE_OUTPUT_PATH 宏 ,用于静态目录

# 只能用于动态so库
set(EXECUTABLE_OUTPUT_PATH ${SOURCE_DIR}/lib)

LIBRARY_OUTPUT_PATH?宏 ,用于动/静态目录

# 适用于动态库/静态库路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

示例:

cmake_minimum_required(VERSION 3.0)
project(cmaketest)

# 输出目录
set(MYPATH /mnt/d/VSProject/cmaketest/outpath)
set(LIBRARY_OUTPUT_PATH ${MYPATH}/lib)

# 示例:
set(SOURCE_DIR /mnt/d/VSProject/cmaketest)
# 包含头文件
include_directories(${SOURCE_DIR}/include)
file(GLOB SRC_LIST ${SOURCE_DIR}/src/*.c)


# add_executable(app  ${SRC_LIST})
# add_library(app STATIC ${SRC_LIST})
add_library(calc SHARED ${SRC_LIST})

执行

# mkdir build
# cd build
# cmake ..
?

# make

这样就会在outpath/lib 目录下生成libcalc.a文件,动态的话就是libcalc.o文件

$ make
[ 25%] Building C object CMakeFiles/app.dir/src/main.c.o
[ 50%] Building C object CMakeFiles/app.dir/src/test1.c.o
[ 75%] Building C object CMakeFiles/app.dir/src/test2.c.o
[100%] Linking C static library ../outpath/lib/libcalc.a
[100%] Built target calc

5.4 静态库,动态库的区别和优缺点

静态库

优点:

  • 静态库被打包到应用程序中加载速度快
  • 发布程序无需提供静态库,移植方便

缺点

  • 相同的库文件数据可能在内存中被加载多份, 消耗系统资源,浪费内存
  • 库文件更新需要重新编译项目文件, 生成新的可执行程序, 浪费时间。

?动态库

优点:

  • 可实现不同进程间的资源共享
  • 动态库升级简单, 只需要替换库文件, 无需重新编译应用程序
  • 可以自由控制何时加载动态库, 不调用库函数动态库不会被加载

缺点:

  • 加载速度比静态库慢,但随着计算机性能的提升可以忽略
  • 发布程序需要提供依赖的动态库

六 链接库文件

6.1 上面已经生成了库文件,那怎样用这个库呢?这时候就需要用链接指令来加载需要的库。当然链接的库可以是自己的库,也可以是其它三方提供的库。

6.2 链接静态库?link_libraries 指令

# 参数是多个静态库的名字
#?可以是全名 libxxx.a
#?也可以是掐头去掉lib后的名字,xxx.a
link_libraries(<static lib> <static lib>...)

我们把源码删掉,保留头文件,库文件和CMakeLists.txt,测试入口main.cpp也可以保留

cmaketest
├── build
├── CMakeLists.txt
├── include
│? ? ?└── head.h
├── outpath
│? ? ?└──?lib
│?? ? ? ??? ?└── libcalc.a ? ? #静态库的名字
└── src
? ? ? ?└── main.cpp

?CMakeLists修改如下:

cmake_minimum_required(VERSION 3.0)
project(cmaketest)

# 输出库文件目录
set(MYPATH /mnt/d/VSProject/cmaketest/outpath)
# set(LIBRARY_OUTPUT_PATH ${MYPATH}/lib)

# 示例:
set(SOURCE_DIR /mnt/d/VSProject/cmaketest)
# 包含头文件
include_directories(${SOURCE_DIR}/include)
file(GLOB SRC_LIST ${SOURCE_DIR}/src/*.c)


# 包含静态库路径
link_directories(${MYPATH}/lib)
# 链接静态库
link_libraries(calc)


add_executable(apptest ?${SRC_LIST})
# add_library(app STATIC ${SRC_LIST})
# add_library(app SHARED ${SRC_LIST})

执行后可以看到生成执行程序apptest成功

$ make
[ 50%] Building C object CMakeFiles/apptest.dir/src/main.c.o
[100%] Linking C executable apptest
[100%] Built target apptest

6.3 链接动态库?target_link_libraries 指令,也可以链接静态库

# target:指定要加载动态库的文件的名字(源文件/动态库文件/可执行文件)
# PRIVATE|PUBLIC|INTERFACE:动态库的访问权限,默认为PUBLIC
# 如果各个动态库之间没有依赖关系,用哪个权限都可以
# 动态库的链接具有传递性,也可以说继承性。
# PUBLIC:库会暴露出去,三方可以看到全部库
# PRIVATE:库仅被link到前面的target中,第三方不能感知你调了啥库
# INTERFACE:库不会被链接到前面的target中,只会导出符号

target_link_libraries(
? ? libname
? ? <PRIVATE|PUBLIC|INTERFACE> ...?)

同样保留动态库so目录如下:

cmaketest
├── build
├── CMakeLists.txt
├── include
│? ? ?└── head.h
├── outpath
│? ? ?└──?lib
│?? ? ? ??? ?└── libcalc.so? ? ?# 动态库的名字
└── src
? ? ? ?└── main.cpp

?CMakeLists修改:?注意程序启动后再去链接动态库

cmake_minimum_required(VERSION 3.0)
project(cmaketest)

# 输出库文件目录
set(MYPATH /mnt/d/VSProject/cmaketest/outpath)
# set(LIBRARY_OUTPUT_PATH ${MYPATH}/lib)

# 示例:
set(SOURCE_DIR /mnt/d/VSProject/cmaketest)
# 包含头文件
include_directories(${SOURCE_DIR}/include)
file(GLOB SRC_LIST ${SOURCE_DIR}/src/*.c)


# 包含静态库路径
# link_directories(${MYPATH}/lib)
# 链接静态库
# link_libraries(calc)

# 启动程序
add_executable(apptest  ${SRC_LIST})
# add_library(app STATIC ${SRC_LIST})
# add_library(app SHARED ${SRC_LIST})

# 程序启动后链接动态库
target_link_libraries(apptest calc)

执行make命令,生成可执行程序

$ make
[ 50%] Building C object CMakeFiles/apptest.dir/src/main.c.o
[100%] Linking C executable apptest
[100%] Built target apptest

6.4 测试静态和动态库是否可用

这时候在build目录下已经生成了一个可执行程序apptest,我们怎样运行这个程序呢

第一步需要给apptest 赋予修改文件的权限

build$ chmod +x apptest

第二步执行" ./ ",来运行该程序 ,,可以看到程序能够正常打印

build$ ./apptest
a , b is20,10
a + b = 30
a - b = 10
a * b = 200
a / b = 2

七 日志 message 命令

7.1 日志用来显示消息

#?type 日志类型:
#?空:重要消息
#?STATUS :非重要消息
#?WARNING:CMake 警告, 会继续执行
#?AUTHOR_WARNING:CMake 警告 (dev), 会继续执行
#?SEND_ERROR:CMake 错误, 继续执行,但是会跳过生成的步骤
#?FATAL_ERROR:CMake 错误, 终止所有处理过程

# message文本消息

message(type message...)

示例:

cmake_minimum_required(VERSION 3.0)
project(cmaketest)

# 输出一般日志信息
message(STATUS "STATUS Message")
# 输出警告信息
message(WARNING "WARNING Message")
# 输出错误信息
message(FATAL_ERROR "FATAL_ERROR Message")

执行cmake指令,生成如下日志

八 List 集合指令操作

8.1 Cmake用法不止上面作用,当然也支持多级嵌套,也支持条件表达式和循环表达式。这里不再细讲,下面说下字符串拼接和List操作相关用法。

8.2 链接字符串

set命令拼接字符串

# 将字符串拼接后赋值给RESULT
set(RESULT ${STRING_1} ${STRING_2} ${STRING_3})

list APPEND 追加字符串

list(APPEND RESULT ${STRING_1} ${STRING_2} ${STRING_3})

8.3?list? REMOVE_ITEM?字符串移除

list(REMOVE_ITEM RESULT ${STRING_1}/main.cpp)

8.4 list??LENGTH 获取长度

list(LENGTH ${STRING_1} RESULT )?

8.5 list用法非常多就不一一演示了,下面常用指令

  • INSERT? ? ? ? ? ? ? ? ? 增
  • REMOVE_ITEM? ? ?删
  • JOIN? ? ? ? ? ? ? ? ? ? ? ?改
  • FIND? ? ? ? ? ? ? ? ? ? ? 查
  • REVERSE? ? ? ? ? ? ?翻转
  • SORT? ? ? ? ? ? ? ? ? ? 排序
  • POP_BACK? ? ? ? ? 移除末尾元素
  • POP_FRONT? ? ? ? 移除开头元素

九 宏定义

9.1 自定义宏:add_definitions(-D宏名称)

cmake_minimum_required(VERSION 3.0)
project(cmaketeat3)
# 自定义 DEBUG 宏
add_definitions(-DDEBUG)
add_executable(app main.c)

main.c文件,?如果定义了DEBUG宏,则会打印出debug消息...

#include <stdio.h>

int main()
{
    int a = 10;
#ifdef DEBUG
    printf("debug消息...\n");
#endif
    printf("hello,word\n");
    return 0;
}

cmake ->?make生成可执行程序app

cmaketest3$ cmake .
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/d/VSProject/cmaketest3


$ make
[ 50%] Building C object CMakeFiles/app.dir/main.c.o
[100%] Linking C executable app
[100%] Built target app

执行app程序

./app

可以看到走到了定义debug消息的地方

$ ./app
debug消息...
hello,word?

对应C++编译方式为

cmaketest3$ gcc main.c -DDEBUG -o app
cmaketest3$ ./app
debug消息...
hello,word

C/C++常用的宏

#空指令无任何效果
#include包含源文件
#define宏定义
#undef取消已定义的宏
#if条件判断,如果给定条件为真,则编译下面代码
#ifdef如果宏已定义,则编译下面代码
#ifudef如果宏没有定义,则编译下面代码
#elif条件判断,else if,如果前面条件不为真,当前条件为真,则编译下面代码
#endif结束条件编译块,#if.....#elif

9.2 CMake中的常见预定义宏

  • PROJECT_SOURCE_DIR :使用cmake命令后紧跟的目录,一般是工程的根目录
  • PROJECT_BINARY_DIR:执行cmake命令的目录
  • CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt所在的路径
  • CMAKE_CURRENT_BINARY_DIR?:target 编译目录
  • EXECUTABLE_OUTPUT_PATH: 重新定义目标二进制可执行文件的存放位置
  • LIBRARY_OUTPUT_PATH?:重新定义目标链接库文件的存放位置
  • PROJECT_NAME:返回通过PROJECT指令定义的项目名称
  • CMAKE_BINARY_DIR:项目实际构建路径,假设在build目录进行的构建,那么得到的就是这个目录的路径

十 调试库

10.1 调试库需要先生成可执行程序

10.1 调试库方式

  • 通过cmake编译生成的可执行程序
  • 当然也可以通过C/C++编译器,来编译main.c入口文件,生成可执行程序

?10.2 我们把库文件,头文件和main.c入口文件放在一个文件夹?

cmaketest2
├── head.h
├── libcalc.a
└── main.c

?编译测试程序main.c

# gcc 编译器
# main.c 测试入口文件
# -o 输出可执行程序
# app可执行程序名字

gcc main.c -o app

但直接执行是有问题的:找不到库里面的方法

$ gcc main.c -o calc
/usr/bin/ld: /tmp/ccG7UGl3.o: in function `main':
main.c:(.text+0x25): undefined reference to `add'
/usr/bin/ld: main.c:(.text+0x37): undefined reference to `sub'
/usr/bin/ld: main.c:(.text+0x49): undefined reference to `mult'
collect2: error: ld returned 1 exit status

所以需要改下,指定库的绝对或者相对路径?

# 编译的时候指定库信息
# -L: 指定库所在的目录(相对或者绝对路径)
# -l: 指定库的名字, 掐头(lib)去尾(.a),这里即app
# -L -l, 参数和参数值之间可以有空格, 也可以没有

gcc main.c -o app -L ./ -l calc

执行上面指令后就看到目录多了个app可执行程序文件

cmaketest2
├── app? ? ? ? ? ? #生成的可执行程序
├── head.h
├── libcalc.a
└── main.c

执行程序

./app

可以看到也可以执行成功

cmaketest2$ ./app
a , b is20,10
a + b = 30
a - b = 10
a * b = 200
a / b = 2

文章来源:https://blog.csdn.net/qq_29848853/article/details/135304261
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。