gcc编译可执行文件和cmake编译可执行文件

gcc编译

gcc的下载(下载mingw,里面包含gcc)
下载安装MinGW-w64详细步骤(c/c++的编译器gcc的windows版,win10真实可用)

gcc编译可执行文件

由源码转换为可执行文件要顺序经过四个步骤
1、预处理(pre processing)
2、编译(compiling)
3、汇编(assembling)
4、链接(linking)

预处理gcc命令:

预处理
gcc -E main.c -o main.i
其中 -E -o 是编译选项,-E 指预处理,-o 指生成的目标文件。生成的为 .i 文件(扩展文件)。

编译gcc命令:

编译
gcc -S main.i -o main.s
其中 -S 指编译。生成的为 .s 文件。

汇编gcc命令:

汇编
gcc -c main.s -o main.o
其中 -c 指汇编。生成的为 .o 文件(目标文件)。

链接gcc命令:

链接
gcc main.o -o main
生成的为可执行文件(windows下为.exe)。


gcc main.c -o main
上述命令由源文件生成可执行文件,过程中依然是先构建目标文件,只不过目标文件在编译可执行文件后删除。

gcc编译可执行文件和cmake编译可执行文件_第1张图片

gcc的编译过程中,不同阶段执行的动作不同。

预处理阶段:

这个步骤的动作会把源文件中引入的头文件展开和一些宏定义的替换。

编译阶段:

这个步骤的动作会先检查源码中是否有语法错误等,然后将高级语言转换为汇编语言。

汇编阶段:

这个步骤的动作会根据编译生成的汇编语言文件,生成二进制代码的目标文件。

链接阶段:

这个步骤是对目标文件中只有声明但没有实现的方法做一个链接库的动作。库包含静态库和动态库,库里包含了方法的实现。

参考
GCC编译的四个阶段
gcc编译的四个过程


静态库和动态库

其中,当一个项目需要引用到别的项目的方法或内容,项目很难将对方的源码引入,这时可以将对方的源码编译成一个库,在编译己方项目时,通过链接库的方法来获取其他项目函数的实现。静态库和动态库的区别为,静态库会编译进可执行文件中。而动态库不随可执行文件,由可执行文件执行到需要动态库的时候才去动态库里找实现。在linux系统中,静态库为.a文件,动态库为.so文件;在windows系统中,静态库为.lib文件,动态库为.dll文件。

gcc编译静态库的方法

ar -rc libtest.a .\test.o

首先由test.c编译出目标文件test.o,根据目标文件生成静态库libtest.a。

gcc编译链接静态库的方法

gcc -o main.exe main.o -L .\test1\ -l test


其中使用 -o 指定目标生成main.exe,是根据main.o生成的。-L 指要链接的文件夹./test/,是所需头文件的路径,-l 指定要链接的库libtest.a,test为库名。


gcc编译动态库的方法

gcc -fPIC -shared test.o -o libtest.so
gcc -fPIC -shared test.c -o libtest.so


在windows系统下动态库的文件格式为dll
gcc -fPIC -shared test.o -o libtest.dll


其中 -shared 说明要编译的是共享库(动态库),动态库可由源文件或目标文件编译而成。

gcc编译使用动态库的方法

如果直接在gcc命令上链接使用动态库会产生报错,找不到动态库。是因为系统默认寻找的动态库路径不包含本项目生成的动态库所在路径,有以下处理:

linux环境下要成功链接动态库有两种方法:
1、将动态库的路径加入到环境变量中

export LD_LIBRARY_PATH=/yourpath:$LD_LIBRARY_PATH


其中 /yourpath 需要修改为动态库所在的绝对路径

2、将动态库复制到 /usr/lib 或 /lib 目录下,这两个是系统默认找动态库的路径

cp libtest.so /usr/lib

windows环境下(目前尝试了一种方法可行):

1、将动态库复制到可执行文件的同一目录下


gcc编译的链接语句和静态库一样

gcc -o main.exe main.o -L . -l test


其中-L . 的 . 指定在当前目录下找

参考帖子:
【gcc】 gcc编译动态库(共享库)、静态库|链接静态库、动态库
GCC编译过程与动态链接库和静态链接库,很详细


cmake编译

cmake和make下载
Windows下CMake的下载与安装详解
windows下安装make

为什么有makefile,cmake,cmakelists

gcc在编译单个文件或少量文件的时候很适用,但随着项目的发展,一个项目往往有大量的文件,此时再一个个敲gcc会稍显麻烦。为了解决文件数过多使用gcc难编译的问题,makefile根据其中的编译规则使用一行shell命令make即可完成大量文件的编译,极大的提高了编译效率。
参考
CMake与CMakeLists是干什么的?

而cmake和cmakelists则是生成makefile的工具和文件。

cmake编译由源文件生成可执行文件的流程分两个阶段:
1、cmake根据cmakelists生成makefile
2、在makefile目录下执行make命令生成可执行文件

编写cmakelists

下面是编写cmakelists的一些简单规则:

main模块

cmake_minimum_required(VERSION 3.24)   # 设置cmake的最小版本

MESSAGE("start")   # MESSAGE可在执行cmakelists的过程中在控制台打印信息

project(c_test01 C)   # 编译的项目名

MESSAGE("middle")
#set(CMAKE_C_STANDARD 11)

add_subdirectory(test1)   # 把子文件夹也要编译

#include_directories(test1)   # 将该文件夹的头文件引入
#link_libraries(test1)   # 链接静态库用,需要在add_executable前使用

add_executable(c_test01 main.c)   # 生成可执行文件

TARGET_LINK_LIBRARIES(${PROJECT_NAME} test1)   # 链接动态库用,在add_executable后使用

MESSAGE("end")

test模块

#add_library(test1 STATIC test.c)   # 生成静态库

add_library(test1 SHARED test.c)   # 生成动态库

其中:
设置cmake版本

cmake_minimum_required(VERSION 3.24)


这里设置编译本项目的cmake最低版本为3.24,一般在cmakelists的开头。可以通过 cmake --version 查看当前的cmake版本,如果当前版本小于上述要求的最低版本,则编译停止。

设置项目名

project(c_test01 C)


声明项目的名字c_test01,后面的 C 是可选项,说明该项目是C语言的

添加子文件夹

add_subdirectory(test1)


编译本项目时将子文件也进行编译,子文件需要包含cmakelists

生成可执行文件

add_executable(c_test01 main.c)


生成可执行文件c_test01,源码为main.c。这里相当于gcc main.c -o mian.exe。

将子文件夹的头文件引入

include_directories(test1)


将该文件夹下的头文件引入到本项目

生成静态库和动态库

add_library(test1 STATIC test.c)
add_library(test1 SHARED test.c)


这两个是在子文件夹下生成静态库和动态库的,test1位库名。STATIC和SHARED指定库为静态库和动态库。库的源码是test.c。

链接静态库

link_libraries(test1)


这个是链接静态库的语句,由于静态库会编译进可执行文件中,所以要在add_executable前使用。

链接动态库

TARGET_LINK_LIBRARIES(${PROJECT_NAME} test1)


这个是链接动态库的语句,由于动态库是在可执行文件执行的过程中才使用,所以在add_executable后使用。

执行cmakelists过程中打印信息

MESSAGE(“start”)
MESSAGE(“middle”)
MESSAGE(“end”)


message是cmakelists的语言规则中可以打印信息到控制台的方法,message可以加一些选项规定打印信息的等级。参考
CMake的内置变量与message打印的用法

cmakelists的语法参考
CMakeLists详解
CMakeLists 入门

使用cmakelists方法

在要编译的cmakelists目录下新建一个build文件夹,这是一种约定俗成的使用习惯。因为执行cmakelists会生成很多文件,为了不影响项目的观感,故将这些文件放在build文件夹下。

mkdir build

然后进入build文件夹执行cmakelists

cd build
cmake ..
# 因为进入到主项目的build的文件夹,而cmakelists在build文件夹的退一层,所以需要 cmake ..
# 如果这步报错可以看看是不是本帖后面遇到的问题

此时build文件夹下会生成makefile和其他文件
gcc编译可执行文件和cmake编译可执行文件_第2张图片
然后就可以在build的目录下执行makefile来生成可执行文件和库文件了

make
# 如果有报错也可以看看是不是本帖后面遇到的问题

gcc编译可执行文件和cmake编译可执行文件_第3张图片
接下来就可以执行可执行文件了,由于这里是在windows环境下,链接动态库需要将动态库复制到可执行文件同一目录下

cp .\test1\libtest1.dll ./

将库文件和可执行文件放在同一目录下
执行可执行文件

.\c_test01.exe

执行成功



初次使用遇到问题

其中,在windows使用cmakelists编译过程中

执行

cmake ..

遇到一个小问题

CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage

这里是cmake编译器没指定,解决方法为

cmake -G "MinGW Makefiles" ..

参考
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage

接着遇到问题

CMake Error: CMake was unable to find a build program corresponding to “MinGW Makefiles”. CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool. CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage

出现这种问题一般是在安装MinGW 时没有下载相应的 make 的文件,解决办法为

打开MinGW Installation Manager,选择make文件下载


参考
CMake Error: CMake was unable to find a build program corresponding to “MinGW Makefiles“ 解决办法

接着在执行make命令的时候,遇到问题

make : 无法将“make”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 所在位置 行:1 字符: 1

在安装mingw的时候已经安装了make的exe,但名字为mingw32-make.exe,所以要么改一下make文件的名字,或者直接使用mingw32-make。

mingw32-make   

参考
VSCODE中使用CMAKE遇到的问题及其解决方法
windows下安装make

在执行可执行文件的过程中,遇到问题

由于找不到dll,无法继续执行代码,重新安装程序

这个是找不到动态库,我的做法是直接把动态库复制到当前可执行文件所在的目录。

cp .\test1\libtest1.dll ./

windows默认查找动态库的方法有几种,

1.exe文件所在的目录下;
2.进程当前的工作目录;
3.Windows系统目录;
4.Windows目录;
5.环境变量Path下的一系列目录;

参考
VS环境下,关于“找不到 **.dll,无法执行代码,重新安装程序可能会解决此问题。”的四种解决方案

你可能感兴趣的:(windows,c语言,c++,linux)