从零学习GCC,Makefile,CMakeList编译

2023-05-16

近期想系统地学习一下C++软件开发,因此记录一下自己的学习笔记,方便复习。大多数内容都是整理搬运别的博主文章内容,加上自己的理解归纳。如果大家想了解更深的内容或者有不明白的地方,可以阅读参考中记录的博客。
平台:Windows10+mingw

参考

【1】Linux编译工具:gcc入门
【2】Linux下gcc生成和使用静态库和动态库详解
【3】一个简单的make&makefile编写指南
【4】Make 编译脚本上手
【5】CMake入门实践

准备

假设我们工程里有三个文件

  1. main.c
#include <stdio.h>
#include <fun.h>

int main(){
    printf("this is main\n");
    fun();
    return 0;
}
  1. fun.c
#include <stdio.h>
#include <fun.h>

void fun(){
    printf("This is fun!\n");
    return;
}
  1. fun.h
#ifndef MAIN_FUN_H
#define MAIN_FUN_H
void fun(void);
#endif

我们要如何编译这个工程呢?

GCC编译

– gcc简介

gcc的全称是GNU Compiler Collection,它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器(GNU C Compiler),现在除了c语言,还支持C++、java、Pascal等语言。gcc支持多种硬件平台。

– gcc编译过程

gcc编译程序主要经过四个过程:

  • 预处理(Pre-Processing)
  • 编译 (Compiling)
  • 汇编 (Assembling)
  • 链接 (Linking)

    预处理实际上是将头文件、宏进行展开。编译阶段,gcc调用不同语言的编译器,例如c语言调用编译器ccl。gcc实际上是个工具链,在编译程序的过程中调用不同的工具。汇编阶段,gcc调用汇编器进行汇编。链接过程会将程序所需要的目标文件进行链接成可执行文件。汇编器生成的是可重定位的目标文件,学过操作系统,我们知道,在源程序中地址是从0开始的,这是一个相对地址,而程序真正在内存中运行时的地址肯定不是从0开始的,而且在编写源代码的时候也不能知道程序的绝对地址,所以重定位能够将源代码的代码、变量等定位为内存具体地址。下面以一张图来表示这个过程,注意过程中文件的后缀变化,编译选项和这些后缀有关。

– gcc编译实例

编译单文件
gcc -c main.c / gcc -o main main.c
区别是前者生成main.o,还需要链接到exe文件,后者会直接生成main.exe
注意1:有一些博主写的是gcc -c main.c -o main,但我发现这样很容易报错,错误原因未知,也许跟系统有关。所以Windows下还是建议最好-o在前。我这里就都写成-o在前了。
注意2:我使用gcc -o main -c main.c编译时无法生成o文件或exe文件,会生成一个没有后缀的文件。使用gcc -o main.o -c main.c是可以的,但使用gcc -o main.exe -c main.c不行。看来-c, -o同时使用只支持生成o文件,而且只支持编译一个文件。好奇怪…

或者一步步进行

1 gcc -o main.i  -E main.c     #对main.c文件进行预处理,生成预处理文件
2 gcc -o main.s -S main.i     #对预处理文件进行编译,生成了汇编文件
3 gcc -o main.o -c main.s   #对汇编文件进行编译,生成了目标文件
4 gcc -o main main.o          #对目标文件进行链接,生成可执行文件

使用gcc时可以加上-Wall选项,否则编译器不会报出警告
gcc -Wall -o bad bad.c

编译多文件
gcc -o main fun1.c fun2.c #生成可执行文件main
注意:这里也是,使用gcc -o main -c fun1.c fun2.c会报错gcc.exe: fatal error: cannot specify -o with -c, -S or -E with multiple files 不确定这是不是linux和windows的区别。

gcc -Wall -o fun1.o -c fun1.c
gcc -Wall -o fun2.o -c fun2.c 
gcc -Wall -o main fun1.o fun2.o

– 使用外部库

库分为静态库和动态库

  • 静态库(Windows->.lib Linux->.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。静态库比较占用磁盘空间,而且程序不可以共享静态库。运行时也是比较占内存的,因为每个程序都包含了一份静态库。
  • 动态库(Windows->.dll Linux->.so):程序在运行的时候才去链接共享库的代码,多个程序共享使用库的代码,这样就减少了程序的体积。值得一提的是,在Windows下的动态链接也可以用到.lib为后缀的文件,但这里的.lib文件叫做导入库,是由.dll文件生成的。

动/静态库的优缺点:C语言的静态链接和动态链接

Linux下:
编译如果直接使用标准库目录的库函数

一般头文件或库文件的位置在标准库目录:

  • /usr/include及其子目录底下的include文件夹
  • /usr/local/include及其子目录底下的include文件夹
  • /usr/lib
  • /usr/local/lib

静态库链接时搜索顺序:

  1. ld会去找GCC命令中的参数-L
  2. 再找gcc的环境变量LIBRARY_PATH
  3. 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初compile gcc时写在程序内的

动态库链接时搜索顺序:

  1. 编译目标代码时指定的动态库搜索路径-L;
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
  4. 默认的动态库搜索路径/lib;
  5. 默认的动态库搜索路径/usr/lib。

例如main.c需要libm.a(标准数学库)
gcc -o main main.c -lm
数学库的文件名是 libm.a。前缀lib和后缀.a是标准的,m是基本名称,GCC 会在-l选项后紧跟着的基本名称的基础上自动添加这些前缀、后缀。
当目录中同时存在同名静态库和动态库时,优先链接动态库。可以添加-static来强制链接静态库。如gcc -o main main.c -lhello -static
如果报错不知道-lc,使用yum install glibc-static

如果需要使用标准库目录之外的库函数,如:

  • <开发目录>/include
  • <开发目录>/lib

方法:

  1. 把链接库作为一般的目标文件,为 GCC 指定该链接库的完整路径与文件名。
    例如,如果链接库名为 libm.a,并且位于 /lib 目录,那么下面的命令会让 GCC 编译 main.c,然后将 libm.a 链接到 main.o:gcc -o main main.c /lib/libm.a
  2. 使用-L选项,为 GCC 增加另一个搜索链接库的目录:gcc -o main main.c -L/lib -lm
  3. 把包括所需链接库的目录加到环境变量 LIB_LIBRARY_PATH 中。export LD_LIBRARY_PATH=\lib:$LD_LIBRARY_PATH

Windows下
编译如果直接使用标准库目录的库函数

静/动态库链接时搜索顺序:

  1. 当前目录(./)
  2. 系统目录(C:/Windows/System32、C:/Windows/System)
  3. Windows目录(C:/Windows)或者环境变量PATH中申明的路径中寻找对应的dll文件。

在程序编译的链接过程中,只有动态链接库dll文件是不够的,还需要使用对应的.lib文件。lib文件中包含了所生成可执行文件所依赖的库函数地址,链接器(linker)需要在lib文件中找到对应的函数符号(symbol)。这样编译生成的可执行文件就可以在运行时找到对应库函数实现代码在内存中的地址,从而调用对应的模块。

如果需要使用标准库目录之外的库函数,如:

  • <开发目录>/include
  • <开发目录>/lib
    这部分内容我只找到了使用Visual Studio的:
  1. 头文件:项目属性>配置属性>C/C++>常规>附加包含目录
  2. lib路径:项目属性>配置属性>链接器>常规>附加库目录
  3. 指定lib:项目属性>配置属性>链接器>输入>附加依赖项

–编译函数生成为外部库

生成为静态库
为了生成.a文件,我们需要先生成.o文件。下面这行命令将我们的hello.o打包成静态库libhello.a:

ar rcs libfun.a fun.o #Linux
ar rcs libfun.lib fun.o #Windows 

ar是gun归档工具,rcs表示replace and create,如果libfun之前存在,将创建新的libfun.a并将其替换。
然后就可以使用我们生成的静态库。(生成的静态库就在工作路径下)

gcc -Wall -o main main.c -L. -lfun #Linux
gcc -Wall -o main main.c libfun.lib #Windows

用MinGW可以生成.a后缀和.lib后缀的静态链接库,但是调用方法不一样。-L的方式貌似只用于Linux, 好晕…

生成为动态库
为了生成.so文件,我们还是需要先生成.o文件。
gcc -shared -fPIC -c fun.c

gcc -shared -fPIC -o fun.so fun.o #Linux
gcc -shared -fPIC -o libfun.dll fun.o #Windows

“PIC”命令行标记告诉GCC产生的代码不要包含对函数和变量具体内存位置的引用,这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样编译出的hello.o可以被用于建立共享链接库。建立共享链接库只需要用GCC的”-shared”标记即可。
然后就可以使用生成的动态库。(生成的动态库就在工作路径下)

gcc -Wall -o main main.c  -L. -lfun #Linux
gcc -Wall -o main main.c  libfun.dll #Linux

–常用参数

  1. –version 查看版本
  2. -v verbose(冗长的),输出编译的详细信息
  3. -std 指定标准
  4. -o 指定输出文件的名称
  5. -Wall 输出所有的警告信息
  6. -c 只将源文件编译为 object 文件(*.o),而不进行链接,之后可以使用 gcc -o myprog.exe file1.o file2.o 将多个 object 文件连接成可执行文件
  7. -shared 编译为共享库(.dll,.so
  8. -S 编译为汇编代码

Make编译

–Make编译简介

假设我们有三个文件,fun.c, main.c, fun.h。
如果使用gcc编译 gcc -o main fun.c main.c -I.
gcc 编译器会编译两个 C 源文件并把可执行程序命名为 main。参数“-I.”用以指示 gcc 在当前目录“.”下寻找头文件 hellomake.h。但是如果我们修改了源文件,那么每次都需要重新输入编译命令。当要编译的源文件很多时,这样做就很没有效率。其次,如果你只对一部分源文件做了修改,每次都重新编译所有的文件耗时且低效。

通过 make 命令,可以将上面的编译进行有效自动化管理。通过将从输入文件到输出文件的编译无则编写成 Makefile 脚本,Make 工具将自动处理文件间依赖及是否需要编译的检测。因为makefile实现了增量编译的效果,执行子任务时它会先检查输入文件是否比输出文件新,如果说输入文件是新的,需要重新生成输出文件,此时才会执行子任务。因此优化了gcc命令编译效率低的问题。

make 命令所使用的编译配置文件可以是 Makefile,makefile 或 GUNMake。其中定义任务的基本语法为:

target1 [target2 ...]: [pre-req-1 pre-req-2 ...]
	    [command1
	     command2
	 ......]

上面形式也可称作是一条编译规则(rule)。其中,
target 为任务名或文件产出。如果该任务不产出文件,则称该任务为 Phony Targets。make 内置的 phony target 有 all, install 及 clean 等,这些任务都不实际产出文件,一般用来执行一些命令。
pre-req123... 这些是依赖项,即该任务所需要的外部输入,这些输入可以是其他文件,也可以是其他任务产出的文件。
command 为该任务具体需要执行的 shell 命令。需要注意的是makefile 中的命令必须以 tab 开始,不能使用空格。

–Makefile编译实例

以上文介绍的三个文件,fun.c, main.c, fun.h。为例。编译它们的makefile为:

all:main

main: main.c fun.c fun.h
	gcc -o main fun.c main.c -I

clean:
	rm main

这里的makefile定义了三个任务:all, main以及clean。调用时可使用make <target name>来单独调用任务。如果只调用make那么只执行all任务。
三个任务中:

  • all 为内置的任务名,一般一个 Makefile 中都会包含,当直接调用 make 后面没有跟任务名时,默认执行的就是 all。此例子中,调用all任务就等于调用main任务,因为 all 的输入依赖为 main文件。Make 在执行任务前会先检查其输入的依赖项,执行 all 时发现它依赖 main 文件,于是本地查找,发现本地没有,再从 Makefile 中查找看是否有相应任务会产生该文件,结果确实有相应任务能产生该文件,所以先执行能够产生依赖项的任务。
  • main为编译工程,产出main.out文件。在这里main为target任务名,main.c, fun.c为pre-req依赖项,gcc命令为command所需的shell命令。
  • clean任务为phony target任务,此clean任务清楚刚才生成的main.out文件。phony任务每次都会执行。

如果一条编译规则中所要执行的shell命令很长,可以通过\[space]来换行,\后的空格是必须的否则识别出错。

–Makefile编译实例(宏/变量)

Makefile 中可使用变量(宏)来让脚本更加灵活和减少冗余。

其中变量使用 $ 加圆括号或花括号的形式来使用,$(VAR),定义时类似于 C 中定义宏,所以变量也可叫 Makefile 中的宏,例如刚才的例子,我们可以使用CC=gcc来定义编译工具,然后makefile将变为:

CC=gcc
CFLAGS = -I.
DEPS = fun.h
all:main

main: mian.c fun.c $(DEPS)
	$(CC) -o main -c main.c fun.c $(DEPS) $(CFLAGS)

clean:
	rm main

这样随着平台或环境的改变,我们可以很方便地修改编译工具。特别是当编译大型工程时。

自动变量
自动变量/Automatic Variables 是在编译规则匹配后工具进行设置的,具体包括:

$@:代表产出文件名
$*:代表产出文件名不包括扩展名
$<:依赖项中第一个文件名
$^:空格分隔的去重后的所有依赖项
$+:同上,但没去重
$?:同上,但只包含比产出更新的那些依赖

这些变量都只有一个符号,区别于正常用字母命名的变量需要使用 $(VAL) 的形式来使用,自动变量无需加括号。利用自动变量,前面实例可以改造成:

CC=gcc
CFLAGS = -I.
TARGET=main

all:$(TARGET)

$(TARGET): main.c fun.c fun.h
	$(CC) -o $@ $^ $(CFLAGS)

clean:
	rm $(TARGET)

搜索路径
当我们想对工程进行分文件夹管理时,可通过 VPATH 指定依赖文件及产出文件的搜索目录。

VPATH = src include
通过小写的 vpath 可指定具体的文件名及扩展名类型,

vpath %.c src
vpath %.h include
此处% 表示文件名。

–Makefile编译实例(规则)

如果在一个工程中我们有很多的文件要产出,那么我们需要写很多的command命令,例如:

Main.o : Main.h Test1.h Test2.h
    g++ -g -o $@ -c $<
Test1.o : Test1.h Test2.h
    g++ -g -o $@ -c $<
Test2.o : Test2.h
    g++ -g -o $@ -c $<

这样代码将非常冗余,包含许多重复命令,此时我们可以利用匹配规则来精简代码。定义一条匹配规则,可以认为像python中的lambda函数一样,制造一个出通用函数。比如:

%.o: %.c
    gcc -o $@ $^

这条编译规则以为这将所有匹配这条的 “将c文件编译为out文件” 任务全部执行。而记录这些任务的语句叫做依赖规则,比如:

Main.o : Main.h Test1.h Test2.h
Test1.o : Test1.h Test2.h
Test2.o : Test2.h

像这种,只定义了产出与依赖没包含任务命令的无则,叫作依赖无则。因为它只定义了某个产出依赖哪些输入,故名。这种规则可达到这种效果,即,右边任何文件有变更,左边的产出便成为过时的了,需要重新编译。依赖规则不能直接调用,它相当于定义了一些输入和输出信息,而实际其中做什么工作需要匹配规则去告知。

匹配规则依赖规则组合起来,我们就可以达到最开始的一次执行多文件产出的效果:

%.o : %.cpp
	g++ -g -o $@ -c $<
Main.o : Main.h Test1.h Test2.h
Test1.o : Test1.h Test2.h
Test2.o : Test2.h

CMake编译

-CMake简介

你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作。

cmake 是 makefile 的上层工具,它们的目的正是为了产生可移植的makefile,并简化自己动手写makefile时的巨大工作量。在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:

  1. 编写 CMake 配置文件 CMakeLists.txt 。
  2. 执行命令 cmake PATH 或者 ccmake PATH 生成 Makefile。其中, PATH 是 CMakeLists.txt 所在的目录。因为CMake往往会生成很多文件,让工程层级看起来不清晰了,所以有一个比较好的方法是再建立一个build文件夹。
  3. 使用 make 命令进行编译。

代码为:

mkdir build
cd build
cmake ..
make

–CMake编译实例

编译单文件
单文件的CMakeLists.txt非常简单。

# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.12)

# 项目名
project (main)

# 添加C++标准
set(CMAKE_CXX_STANDARD 11)

# 指定生成目标
add_executable(main main.c)

然后按照简介中的1,2,3运行即可。需要注意的是:这是Linux下的运行方式,在Windows中,如果直接cmake .的话不会生成Makefile,需要使用cmake . -G "Unix Makefiles"替代。

编译多文件
假设我们有三个文件:main.c, fun.c, fun.h。我们要只要将新的fun.c和fun.h写入CMakeLists里即可。

# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.12)

# 项目名
project (main)

# 添加C++标准
set(CMAKE_CXX_STANDARD 11)

# 包含文件目录
include_directories(./)

# 指定生成目标,将fun.c也加入进去
add_executable(main main.c fun.c)

当文件比较多的时候,我们可以使用aux_source_directory命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。使用语法为:aux_source_directory(<dir> <variable>)
例如上述例子可以改为:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.12)

# 项目名
project (main)

# 添加C++标准
set(CMAKE_CXX_STANDARD 11)

# 包含文件目录
include_directories(./)

# 查找源文件,存入src变量
aux_source_directory(. src)

# 指定生成目标
add_executable(main ${src})

PS:我尝试的时候遇到了previous definition here错误。这里也记录一下。

  1. 第一种是在include <xxx.h> 时写成了 include <xxx.c>。
  2. 一个函数多次重定义,应添加以下宏定义。
#ifndef TEST_H
#define TEST_H
// code here
#endif
  1. 源码直接写在头文件.h里没有对应的.cpp文件
    需要每个函数前添加 inline 声明
 inline void assign(sqlite3_stmt* stmt, int& item, size_t I){
        item = sqlite3_column_int(stmt, I);
 }

编译多目录多文件
假设我们把fun.c放入文件夹src中,fun.h放入文件夹include中,需要怎么修改CMakeLists呢。其实也很简单,只要活用命令include_directoriesaux_source_directory就可以了。例如我们可以将CMakeLists改为:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.12)

# 项目名
project (main)

# 添加C++标准
set(CMAKE_CXX_STANDARD 11)

# 包含文件目录
include_directories(./include)

# 查找源文件
aux_source_directory(. src1)
aux_source_directory(./src src2)

# 指定生成目标
add_executable(main ${src1} ${src2})

创建使用链接库

假设我们需要将fun.c构建成一个静态库或者动态库。我们需要将fun.c和fun.h放在一个目录下,并构建另一个CMakeLists。即:

./
  |
  +---CMakeLists.txt
  |
  +---main.c
  |
  +---src
      +---CMakeLists.txt  #生成链接库
      |
      +---fun.c
      |
      +---fun,h

CMake中生成链接库的方法是很相似的。如果我们想要生成一个静态库libfun.a或者动态库libfun.so。则CMakeLists可以写成:

# 添加头文件搜索路径
include_directories(.)

# 定义源文件列表
aux_source_directory(. src)

# 指定生成目标 目标名字随便写
add_library(fun ${src}) #静态库
add_library(fun SHARED ${src}) #动态库

add_executable()用来构建可执行程序,这里用add_library()来构建静态库或者动态库。
生成完的libfun.a/libfun.sosrc下。如果我们要调用这个库,那么需要更改CMakeLists为:

# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.12)

# 项目名
project (main)

# 添加C++标准
set(CMAKE_CXX_STANDARD 11)

# 包含文件目录, fun.h已经被放入src下了
include_directories(./src)

# 添加引用的外部库的搜索路径
link_directories(./src)

# 指定生成目标
add_executable(main main.c)
# 将静态库链接到应用程序
target_link_libraries(main libfun.a) #这个命令只链接静态库
target_link_libraries(main fun) #这个命令自动搜索动态库和静态库
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从零学习GCC,Makefile,CMakeList编译 的相关文章

  • Gcc 4.2 版本缺失

    在我的带有 osx lion 和 XCode 4 1 的新 macbook pro 上 我遇到了一些 gcc 问题 In usr bin我找不到gcc 4 2 我只有以下版本 i686 apple darwin11 llvm gcc 4 2
  • 构建 makefile 依赖/继承树

    如果我解释得不好或者问了一些明显的问题 我很抱歉 但我是 Linux 内核的新手 而且有点深入 我们有一个嵌入式 Linux 系统 它附带一个 文档非常糟糕的 SDK 其中包含数百个文件夹stuff 大多数文件夹包含rules make m
  • gcc 中 -g 选项的作用是什么

    我看到很多关于 gdb 的教程要求在编译 c 程序时使用 g 选项 我无法理解 g 选项的实际作用 它使编译器将调试信息添加到生成的二进制文件中 此信息允许调试器将代码中的指令与源代码文件和行号相关联 拥有调试符号可以使某些类型的调试 例如
  • @:(符号冒号)在 Makefile 中意味着什么?

    Makefile 中的以下内容有何作用 rule deps 我在制作手册中似乎找不到这个 它的意思是 不要在输出中回显此命令 所以这条规则是说 执行 shell 命令 并且不回显输出 当然是shell命令 是一个空操作 所以这就是说 什么都
  • 什么是“制定目标”?

    为什么我需要制作一个make target在能够构建我的源代码之前 更具体地说 什么是制定目标 http publib boulder ibm com infocenter rsdvhelp v6r0m1 index jsp topic o
  • Ubuntu 11.10 上的 c 数学链接器问题 [重复]

    这个问题在这里已经有答案了 我从 Ubuntu 升级后出现了一些奇怪的错误 10 11 11 04 i dont know 到 11 10 我正在得到一个undefined reference to sqrt 使用 math h 时并与 l
  • 避免重复 GNU Make 规则

    我一直在编写一个执行一些依赖项生成的 Makefile 我发现自己必须重复规则 因为 遗留 代码库包含以下内容的混合 cpp and cc文件 好像有点难看 无论如何 是否可以指定目标的先决条件可以是 cpp or cc files 所以而
  • 将环境变量从 Makefile 导出到用户态环境

    我正在研究如何从 Makefile 环境变量导出以在用户环境中公开 因此应该可以从用户 shell 访问从 Makefile 导出这些变量 我努力了make s export https www gnu org software make
  • 为什么总是./configure;制作;进行安装;作为 3 个单独的步骤?

    每次从源代码编译某些内容时 都会经历相同的 3 个步骤 configure make make install 我明白 将安装过程分为不同的步骤是有意义的 但我不明白 为什么这个星球上的每个编码员都必须一次又一次地编写相同的三个命令才能完成
  • 抑制 makefile 中命令调用的回显?

    我为一个作业编写了一个程序 该程序应该将其输出打印到标准输出 分配规范需要创建一个 Makefile 当调用它时make run gt outputFile应该运行该程序并将输出写入一个文件 该文件的 SHA1 指纹与规范中给出的指纹相同
  • 如何在 GCC 5 中处理双 ABI?

    我尝试了解如何克服 GCC 5 中引入的双重 ABI 的问题 但是 我没能做到 这是一个重现错误的非常简单的示例 我使用的GCC版本是5 2 如您所见 我的主要函数 在 main cpp 文件中 非常简单 main cpp include
  • 具有两个同名目标的 Makefile

    我有一个包含包含语句的 makefile 我无法控制包含的 makefile 的内容 不过 我希望能够在 某些 不是全部 目标之前添加一些预处理步骤 考虑以下示例 install echo install target include ot
  • 在GCC中添加父目录的包含路径

    我想将父目录中的文件包含在我正在处理的项目中 所有的头文件都在父目录中 有没有办法在命令行上使用 I 来搜索父目录中的包含而不使用绝对路径 我知道我可以使用 makefile 解决这些问题 并且我可能最终会这样做 但我想知道是否有一个可以使
  • C++11 Geany 设置

    我正在学习 C 我需要在 Geany 中为 C 11 正确设置编译和构建命令 我以为我的理解是正确的 但是当使用时auto 我收到以下错误 warning auto will change meaning in C 0x please re
  • 链接器问题 - 未定义的引用

    我的编译器有问题 告诉我有一个 未定义的引用 我想在库中使用的函数 让我分享一些有关该问题的信息 我正在用 gcc 交叉编译 C 语言 我正在调用一个库函数 该函数通过包含的标头访问 其中包含另一个标头 其中包含原型 我已经使用 I 包含了
  • C 中“complex”的默认类型

    根据我读过的文档 C99 和更高版本的支持float complex double complex and long double complex作为复杂类型 但是 此代码在使用时编译时不会发出警告gcc Wall Wextra inclu
  • 除了 gcc 之外,还有哪些编译器可以对代码进行向量化?

    GCC can 矢量化循环 ftp gcc gnu org pub gcc summit 2004 Autovectorization pdf当指定某些选项并给出正确的条件时 会自动进行 是否还有其他广泛可用的编译器可以执行相同的操作 IC
  • 如何编译一个简单的 multiboot2 裸机可执行文件?

    我想开始写一个操作系统内核 然后 我找到了一个document http nongnu askapache com grub phcoder multiboot pdf引入 multiboot2 规范 有三个示例代码文件 名为boot S
  • 为什么这个 makefile 在“make clean”上执行目标

    这是我当前的 makefile CXX g CXXFLAGS Wall O3 LDFLAGS TARGET testcpp SRCS main cpp object cpp foo cpp OBJS SRCS cpp o DEPS SRCS
  • long double(GCC 特定)和 __float128

    我正在寻找有关的详细信息long double and float128在 GCC x86 中 更多是出于好奇而不是因为实际问题 可能很少有人需要这些 我只是有史以来第一次 truly需要一个double 但我想知道你的工具箱里有什么以及它

随机推荐

  • Cannot find module ‘body-parser‘

    node modules下模块缺失 解决方案 xff1a npm install span class token operator span save body span class token operator span parser
  • C#中struct和class的区别

    本文详细分析了C 中struct和class的区别 xff0c 对于C 初学者来说是有必要加以了解并掌握的 简单来说 xff0c struct是值类型 xff0c 创建一个struct类型的实例被分配在栈上 class是引用类型 xff0c
  • 沁恒MCU串口使用指南

    转载注明出处 沁恒MCU串口使用指南 xff1a 适用于WCH的32位MCU和CH559 558单片机 只描述TTL电平的TX 43 RX形式的常规串口 xff0c 流控 xff0c RS232 RS485不在文章涉及范围之内 大部分8位机
  • ubuntu安装网络调试助手

    下载mNetAssist安装包 链接 https pan baidu com s 1eHalZSnsVKXRERmIOCfj0w 提取码 bhxs新建终端并切换到安装包所在目录sudo dpkg i mNetAssist release a
  • .s19 文件转换为 .hex 和 .bin文件的方法

    使用STVD开发时 xff0c 编译后产生的是 s19 文件 xff0c 与Keil 和 IAR常见的 hex bin文件不同 xff0c 那么如何将 s19文件转换为常见的文件格式呢 xff1f 一 获取工具 burner 下载链接 xf
  • VS Code中C/C++ 无法跳转到定义的解决办法

    VS code的跳转功能一直很迷 xff0c 时好时坏 xff0c 有些新的工程环境干脆用不了 经过一遍遍的baidu加上自己的摸索 xff0c 总结出一套经验 xff0c 应该可以解决大部分的情况了 一 首先 xff0c 当然是安装插件了
  • 使用void*强转函数指针(编辑中)

    别把函数名当成函数 xff0c just a 变量 typedef void AirCb void 空回调函数 typedef int aimFunction int para1 char para2 int para3 要传递的目标函数
  • KoroFileHeader 配置

    一 安装插件 二 Github 地址 https github com OBKoro1 koro1FileHeader 三 快速上手 https github com OBKoro1 koro1FileHeader wiki E5 AE 8
  • 网络接入与身份认证简介

    目录 1 认证简介 2 常见认证机制 基于口令的身份认证机制 挑战 响应认证机制 EAP认证机制 3 公钥认证机制 4 使用认证机制的认证协议 RADIUS认证协议 TACACS 43 认证协议 Kerberos认证协议 LDAP协议 5
  • VS Code常见问题

    1 更改自动补全 xff08 联想 xff09 快捷键的方法 文件 gt 首选项 gt 键盘快捷方式 搜索trigger 找到该选项 xff0c 更改快捷键 2 当鼠标悬停在枚举值上 xff0c 不能显示当前序号 a 打开setting j
  • 用Keil编译C51和ARM时,分别生成.Bin文件的方法

    一 C51 1 使用srec cat exe a Keil工程需生成 hex文件 b 将srec cat exe放在工程路径中任意文件夹下 c 新建一个文本文档 xff0c 之后填写如下内容 xff0c 保存后更名为 1 bat xff08
  • Keil新建Stm32标准工程中 Preprocessor Symbols的作用

    xff08 转自正点原子的回复 xff09 标准的工程新建办法 是要添加 34 USE STDPERIPH DRIVER STM32F10X HD的 USE STDPERIPH DRIVER 是告诉编译器 我们需要使用标准库了 实际上是 c
  • 单片机中利用Union联合体打印输出浮点数(小数)

    方法一 xff1a 指针 UART串口有一个缺点 xff0c 就是发送和接受是一个字节一个字节的接收 xff0c 如果发送的浮点数那可怎么办啊 xff1f 有人会说 xff0c 那就一个字节一个字节发送啊 那么 xff0c 我先定义一个do
  • 用 IAR 开发 STM8 时,简单软件延时不起作用的原因

    近期有幸接手了前任工程师遗留的项目 xff0c MCU 选择的是 STM8L151XX xff0c 开发工具使用的是 IAR 打开祖传代码后 xff0c 通读了一遍 xff0c 就用ST Link烧录进去跑程序 xff0c 结果发现和预想的
  • 基于SX1276芯片的 LORA 技术开发详解

    一 简介 LORA xff0c 是 Long Range 的简称 LORA 技术 xff0c 源自于美国的升特公司 xff08 Semtech xff09 xff0c 是一种用于中 长距离传输的技术 xff0c 相关信息主要从升特公司官网获
  • Linux下用C语言将一个字符串格式(char*)的MAC地址转换为十六进制数组

    include lt stdio h gt include lt stdlib h gt unsigned char a2x const char c switch c case 39 0 39 39 9 39 return unsigne
  • 超声波换能器的主要参数解读,全!

    1 导纳是阻抗的倒数 xff0c 也就是一个代表困难程度的量 xff0c G为电导 xff0c B为电纳 导纳Y是一个复数 xff0c Y 61 G 43 jB xff1b 实部为电导 xff0c 虚部为电纳 G越大 xff0c 说明电荷越
  • 温度对超声波换能器的影响

    我们都知道超声波换能器的主要参数有 xff1a 谐振频率 反谐振频率 谐振阻抗 反谐振阻抗 输出幅值 静态电容等 在平时使用换能器的时候 xff0c 除了超声波换能器有自身损耗的影响外 xff0c 很可能使用场合出现在室内或室外 xff0c
  • RC522模块学习

    目录 1 原理简介 2 SPI通信 3 获取卡号实验 3 驱动函数 参考 xff1a https www cnblogs com ivantang p 3904025 html https xiaolong blog csdn net ar
  • 从零学习GCC,Makefile,CMakeList编译

    近期想系统地学习一下C 43 43 软件开发 xff0c 因此记录一下自己的学习笔记 xff0c 方便复习 大多数内容都是整理搬运别的博主文章内容 xff0c 加上自己的理解归纳 如果大家想了解更深的内容或者有不明白的地方 xff0c 可以