松垮垮 松垮垮
首页
  • GPU并行编程
  • 图形学
  • 归并算法
  • 计算机视觉
  • css
  • html
  • JavaScript
  • vue
  • 压缩命令
  • cmdline
  • Docker
  • ftrace跟踪技术
  • gcov代码覆盖率测试
  • GDB
  • git
  • kgdb
  • linux操作
  • markdown
  • systemtap
  • valgrind
  • 设计模式
  • 分布式
  • 操作系统
  • 数据库
  • 服务器
  • 网络
  • C++
  • c语言
  • go
  • JSON
  • Makefile
  • matlab
  • OpenGL
  • python
  • shell
  • 正则表达式
  • 汇编
  • GPU并行编程
  • mysql
  • nginx
  • redis
  • 网络
  • 计算机视觉
  • 进程管理
  • linux调试
  • 【Python】:re.error bad escape i at position 4
  • 搭建ai知识助手
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

松垮垮

c++后端开发工程师
首页
  • GPU并行编程
  • 图形学
  • 归并算法
  • 计算机视觉
  • css
  • html
  • JavaScript
  • vue
  • 压缩命令
  • cmdline
  • Docker
  • ftrace跟踪技术
  • gcov代码覆盖率测试
  • GDB
  • git
  • kgdb
  • linux操作
  • markdown
  • systemtap
  • valgrind
  • 设计模式
  • 分布式
  • 操作系统
  • 数据库
  • 服务器
  • 网络
  • C++
  • c语言
  • go
  • JSON
  • Makefile
  • matlab
  • OpenGL
  • python
  • shell
  • 正则表达式
  • 汇编
  • GPU并行编程
  • mysql
  • nginx
  • redis
  • 网络
  • 计算机视觉
  • 进程管理
  • linux调试
  • 【Python】:re.error bad escape i at position 4
  • 搭建ai知识助手
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • C++

    • C++11
    • C++17
    • c++规范
    • cmake和宏开关
      • 基本
        • 对于同一目录下的文件
        • 对于不同目录下的文件
        • 对于正规的组织结构
      • 动态库和静态库的编译控制
      • 对库进行链接
      • 添加编译或控制选项
        • 编译选项添加
        • 添加控制选项选择文件编译
        • 添加控制选项选择宏开关
      • debug和release模式
        • 哪些情况下release版本会出错
        • 调试方法
      • debug模式下正常运行,release模式下运行出错
    • 为了高效
    • 作用域和生命周期
    • 关键字
    • 内存分配
    • 基础
    • 容器
    • 对象和类
    • 线程
  • c语言
  • Go

  • JSON
  • Makefile
  • matlab

  • OpenGL
  • python

  • shell
  • 正则表达式
  • 汇编
  • 语言
  • C++
songkuakua
2025-02-15
目录

cmake和宏开关

# cmake和宏开关

Owner: -QVQ-

# cmake

# 基本

aux_source_directory(dir var) cmake中提供把指定目录下所有源文件储存在一个变量中的函数

add_subdirectory 可以向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置

include_directories()函数包裹头文件路径,要么通过如下方式给出头文件位置

add_executable(生成的exe名 源文件) 指定生成可执行文件名和相关源文件

set(变量名 文件名……)新建变量来存放需要的源文件

EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置

PROJECT_SOURCE_DIR:工程的根目录

add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)

set_target_properties: 设置最终生成的库的名称,还有其它功能,如设置库的版本号等等

LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录

find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径,其它用法可以参考cmake文档

find_library函数默认查看动态库,如下方式可以指定使用动态库还是静态库find_library(TESTFUNC_LIB libtestFunc.so)

target_link_libraries: 把目标文件与库文件进行链接

# 对于同一目录下的文件

目录下创建CMakeLists.txt,cmake无视大小写

cmake_minimum_required(VERSION 3.15)# 指定使用CMake的最低版本号

project(Tutorial)# 项目名字

add_executable(Tutorial tutorial.cpp 多个文件...)# 指定生成可执行文件名和相关源文件
1
2
3
4
5

执行 cmake . 生成makefile和其他文件

执行make开始编译生成可执行文件

cmake中提供把指定目录下所有源文件储存在一个变量中的函数

aux_source_directory(dir var)

第一个是指定目录,第二个是存放源文件列表的变量

cmake_minimum_required (VERSION 2.8)

project (demo)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})
1
2
3
4
5
6
7

如果只要部分文件,可以用set命令去新建变量来存放需要的源文件

cmake_minimum_required (VERSION 2.8)

project (demo)

set( SRC_LIST
	 ./main.c
	 ./testFunc1.c
	 ./testFunc.c)

add_executable(main ${SRC_LIST})
1
2
3
4
5
6
7
8
9
10

# 对于不同目录下的文件

用include_directories()向工程加入多个头文件的搜索路径,路径间用空格分隔

用多个变量将不同路径下的文件加入进去

cmake_minimum_required (VERSION 2.8)

project (demo)
# 加入路径
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})
# 目录结构:
# CMakeLists.txt
# main.c
# **test_func**
# --1.c
# --1.h
# **test_func1**
# --2.c
# --2.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

对于main.c ,如果引用了1.h和2.h,要么通过include_directories()函数包裹头文件路径,要么通过如下方式给出头文件位置

#include "test_func1/2.h"

# 对于正规的组织结构

正规一点来说,一般会把源文件放到src目录下,把头文件放入到include文件下,生成的对象文件放入到build目录下,最终输出的elf文件会放到bin目录下

# 目录结构:
# **bin**
# **build**
# **include**
# --1.h
# --2.h
# **src**
# --1.c
# --2.c
# --main.c
1
2
3
4
5
6
7
8
9
10

通常在最外层建一个CMakeLists.txt

cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (src)
1
2
3
4
5

add_subdirectory 可以向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置

此时执行cmake 会进入src目录下去找CMakeLists.txt,所以在src目录下也建立一个CMakeLists.txt,内容如下,

cmake自带的预定义变量

# 添加当前路径下的所有文件
aux_source_directory (. SRC_LIST)
# 添加头文件
include_directories (../include)
# 指定生成的可执行文件名和源文件
add_executable (main ${SRC_LIST})
# 这里的set指把存放elf文件的位置设置为工程根目录下的bin目录
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
1
2
3
4
5
6
7
8
  • EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置
  • PROJECT_SOURCE_DIR:工程的根目录

此时切换到build路径下,输入cmake .. 在build下生成中间文件,然后在build下运行make

在这个例子下写了两个CMakeLists.txt,如果只想要一个CMakeLists.txt,只需把根目录下的CMakeLists.txt改为

cmake_minimum_required (VERSION 2.8)

project (demo)
# 相当于不设置src文件
# 后面的四步等同里层的CMakeLists.txt文件
aux_source_directory (src SRC_LIST)

include_directories (include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
1
2
3
4
5
6
7
8
9
10
11
12

# 动态库和静态库的编译控制

只编译出动态库和静态库,让其他程序去使用

# 对于如下结构目录
# build
# CMakeLists.txt
# lib
# testFunc
# --testFunc.c
# --testFunc.h
1
2
3
4
5
6
7

在build下运行cmake,并把生成的库文件放到lib下

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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)

set_target_properties: 设置最终生成的库的名称,还有其它功能,如设置库的版本号等等

LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录

# 对库进行链接

# 对于如下目录结构
# bin
# build
# CMakeLists.txt
# src
# --main.c
# testFunc
# --inc
# ------testFunc.h
# --lib
# ------libtestFunc.a
# ------libtestFunc.so
1
2
3
4
5
6
7
8
9
10
11
12

工作目录下的CMakeLists.txt

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})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径,其它用法可以参考cmake文档
  • target_link_libraries: 把目标文件与库文件进行链接

linux下通过readelf -d ./xx 可以查看源文件的库依赖

# 添加编译或控制选项

# 编译选项添加

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)
1
2
3
4
5
6
7
8
9

# 添加控制选项选择文件编译

option()第一个参数是这个option的名字,第二个参数是字符串,用来描述这个option是来干嘛的,第三个是option的值,ON或OFF,不写就是默认OFF。

# 目录结构为
# bin
# build
# CMakeLists.txt
# src
# ---CMakeLists.txt
# ---main1.c
# ---main2.c
1
2
3
4
5
6
7
8

外层的CMakeList.txt

cmake_minimum_required(VERSION 3.5)
project(demo)

option(MYDEBUG "enable debug compilation" OFF)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_subdirectory(src)
1
2
3
4
5
6
7
8

src目录下的CMakeList.txt

cmake_minimum_required (VERSION 3.5)

add_executable(main1 main1.c)
# 依据前面的开关决定这里是否编译main.c
if (MYDEBUG)
    add_executable(main2 main2.c)
else()
    message(STATUS "Currently is not in debug mode")    
endif()
1
2
3
4
5
6
7
8
9

编译时在build目录下输入cmake .. -DMYDEBUG=ON,这样就可以编译出main1和main2

# 添加控制选项选择宏开关

mian.c内容如下

#include <stdio.h>

int main(void)
{
#ifdef WWW1
    printf("hello world1\n");
#endif    

#ifdef WWW2     
    printf("hello world2\n");
#endif
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

CMakeList.txt中的内容如下

cmake_minimum_required(VERSION 3.5)
project(demo)
# 设置可执行文件的路径
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 设置宏开关
option(WWW1 "print one message" OFF)
option(WWW2 "print another message" OFF)
# 根据宏开关在make 的时候决定是否加上宏定义
if (WWW1)
    add_definitions(-DWWW1)
endif()

if (WWW2)
    add_definitions(-DWWW2)
endif()
# 决定可执行文件名称和源文件位置
add_executable(main main.c)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

分别安装如下命令能打印出不同的内容

  • cmake .. -DWWW1=ON -DWWW2=OFF && make
  • cmake .. -DWWW1=OFF -DWWW2=ON && make
  • cmake .. -DWWW1=ON -DWWW2=ON && make

注意:如果有多个options选项,先用cmake设置了A,下次再调用cmake设置B,这个A的状态会沿用上次的

所以如果option有变化,要么删除上次执行cmake时产生的缓存文件,要么把所有的option都显式的指定其值。

# 控制语句

IF (CMAKE_BUILD_TYPE STREQUAL DEBUG)
    ADD_DEFINITIONS(-DDEBUG)
ENDIF()
//如果CMAKE_BUILD_TYPE的值等于DEBUG执行语句
1
2
3
4

cmake中if语句除了STREQUAL关键字,还有以下关键字可以使用:

  • STREQUAL: 判断字符串是否相等
  • STRLESS: 判断字符串是否小于
  • STRGREATER: 判断字符串是否大于
  • STRLESS_EQUAL: 判断字符串是否小于等于
  • STRGREATER_EQUAL: 判断字符串是否大于等于
  • EQUAL: 判断数字是否相等
  • LESS: 判断数字是否小于
  • GREATER: 判断数字是否大于
  • LESS_EQUAL: 判断数字是否小于等于
  • GREATER_EQUAL: 判断数字是否大于等于
  • AND: 逻辑与
  • OR: 逻辑或
  • NOT: 逻辑非

这些关键字可以用来进行条件判断,根据判断结果执行相应的操作。

# cmake中的宏开关

为了调试程序,经常需要加一些输出语句,可以定义一个debug宏作为调试输出的开关。

实例代码:

#include <stdio.h>

int main(void)
{
    int i, sum;

    for (i = 1, sum = 0; i <= 5; i++)
    {
        sum += i;
#ifdef DEBUG
        printf("sum += %d is %d\n", i, sum);
#endif
    }
    printf("total sum is %d\n", sum);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

使用gcc编译时用-D打开这个宏

gcc -D DEBUG test.c

更进一步的,自己写输出宏函数,使用时用自己的宏函数,避免了每次都写#ifdef DEBUG

#include <stdio.h>
#ifdef DEBUG
#define DBGprint(...) printf(__VA_ARGS__)
#else
#define DBGprint(...)
#endif

int main(void)
{
    int i, sum;

    for (i = 1, sum = 0; i <= 5; i++)
    {
        sum += i;
        DBGprint("sum += %d is %d\n", i, sum);
    }
    printf("total sum is %d\n", sum);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

在cmake中打开宏

在CMakeLists文件中添加DEBUG的定义:

IF (CMAKE_BUILD_TYPE STREQUAL DEBUG)
    ADD_DEFINITIONS(-DDEBUG)
ENDIF()
1
2
3

在cmake的时候设置参数DCMAKE_BUILD_TYPE 为 DEBUG:

$ cmake .. -DCMAKE_BUILD_TYPE=DEBUG $ make -j4

cmake -D<variable>=<value> 定义 CMake 变量(-D后面没有空格)。<variable> 为变量名,<value> 为变量的值。可以使用多个 -D 选项来定义多个变量。

cmake CFLAG=-std 为gdb添加选项

cmake -DCMAKE_CXX_STANDARD=11 指定g++的版本为c++11

cmake .. -DCMAKE_BUILD_TYPE=Debug

指定编译出来的文件为可调式的不做优化的,release是发行版本

# cmake中set

set(CMAKE_CXX_STANDARD_REQUIRED ON)

设置指定的C++编译器版本是必须的,如果不设置,或者为OFF,则指定版本不可用时,会使用上一版本。

set(CMAKE_CXX_STANDARD 11)

指定g++的编译选项

set(CMAKE_C_FLAGS_RELEASE "-O0 -ggdb")

指定gcc的编译选项

set(CMAKE_BUILD_TYPE DEBUG)
set(CMAKE_C_FLAGS "-O0 -ggdb")
set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb")
set(CMAKE_C_FLAGS_RELEASE "-O0 -ggdb")
set(CMAKE_CXX_FLAGS "-O0 -ggdb")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "-O0 -ggdb")
1
2
3
4
5
6
7

# 一些配置选项

cmake_minimum_required(VERSION 3.10)

设置cmake的最低版本

# 理论

# debug和release模式

两者并没有本质界限,只是编译选项的不同,可以自定义编译选项以设置不同的版本

主要编译选项

Debug版本:

/Od 关闭优化开关

/D ”_DEBUG“ 打开编译调试代码的宏定义(主要是assert函数)

/ZI 创建Edit and continue编辑继续数据库,这样在调试的过程中修改了源代码不需重新编译

/GZ 帮助捕获内存错误{

主要功能:

1 初始化内存和变量,用一些特殊的值初始化变量,堆区、内存等,这些值一般不会使用,也容易辨认,利于在debug版本中发现release版才会遇到的错误

2 检查函数指针调用函数时是否匹配

3 函数返回当前检查栈指针,确认未被修改

}

/MDd /MLd 或/MTd 使用Debug、runtime、library(调试版本运行时刻函数库)

Release版本:

/MD /MT 或ML 使用发布版本的运行时刻函数库

/O1 /O2优化开关,是程序最小或最快

/D ”NDEBUG“关闭条件编译调试代码开关(不编译assert函数)

/GF 合并重复的字符串,将字符串常量放到只读内存

如果Debug版本有错,Release正常,程序肯定有问题,只是某次运行没有表现出来

# 哪些情况下release版本会出错

优化问题是造成错误的主要原因

一、帧指针(Frame Pointer即FPO)

函数的声明和实现不同(数据类型不同),Debug模式下可以通过EBP寄存器保存的地址实现,release会省略EBP栈基址指针,通过全局指针访问栈。

C++的强类型能检查出,但强制类型转换就不行

二、volatile型变量

有时一些变量放在寄存器中,其他进程直接对变量内存进行修改,多线程下,如果发现某个值和预期不符,可以把认为可以的变量加上volatile

三、变量优化

void abc(void) {
	int i = 1;
	int a[4];
	{
		int j;
		j = 1; //j的空间还没有回收
	}
	a[-1] = 1; //此时虽然j已经离开了作用域,当其空间并未回收,从而掩盖了越界
	std::cout<<a[-1];
	//a[3] = 1;
}
int main()
{
	abc();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

函数有未使用的变量在debug版本中它可能掩盖数组越界

而release版本由于j未使用则可能会被优化掉,从而使栈被破坏,从而程序终止

四、 /GZ选项

会造成Debug版本错误,而Release版本正常,因为Debug版本变量随机分配,可能指向应该有效地址而掩盖了非法访问

# 调试方法

修改编译选项来缩小错误范围

debug版中使用/W4警告级别,获得最多的错误信息

#progma warning(disable: 4702) //禁止某个错误
#progma warning(default: 4702) 
#progma warning(push, 3)  //设置警告级别为/W3
#progma warning(pop) //重设警告级别
1
2
3
4

# debug模式下正常运行,release模式下运行出错

问题:调试时发现代码进入了第三方库的时候,构建了函数栈,还没执行第一条函数的时候发生段错误

分析:编译时开启了release模式时运行错误,使用debug模式运行正确

上次更新: 2025/02/21, 14:57:10
c++规范
为了高效

← c++规范 为了高效→

最近更新
01
搭建ai知识助手
02-23
02
边缘检测
02-15
03
css
02-15
更多文章>
Theme by Vdoing | Copyright © 2025-2025 松垮垮 | MIT License | 蜀ICP备2025120453号 | 川公网安备51011202000997号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 纯净模式