前言
编译分四步
预处理:将不同文件中的源程序聚合到一起,并进行宏替换
编译:将高级语言(X=2)翻译成汇编语言或机器语言的过程
汇编:将汇编语言(MOV X,2)翻译成机器语言的过程
链接:将多个可重定位(内存的起始地址不固定)的机器代码文件链接到一起,解决外部内存地址问题
gcc
# gcc -E test.c -o test.i
-E 让编译器只对输入文件进行预处理
# gcc -S test.i -o test.s
-S 产生汇编语言文件,扩展名是.s
# gcc -c test.s -o test.o
-c 将汇编语言转化为机器语言
# gcc test.o -o test
-o 为产生的可执行文件指定文件名,若不加-o 则默认文件名为a.out
简单点一步到位
# gcc -c test.c -o test
直接生成一个test可执行程序
通过./test调用该程序
处理多源文件目录
(以下的树结构是通过tree命令实现的)
先给代码,可以自己动手试试
main.cc
#include <iostream>
#include "swap.h"
using namespace std;
int main()
{
int a=1,b=10;
cout<<"交换前"<<"a = "<<a<<" "<<"b = "<<b<<endl;
swap(a,b);
cout<<"交换后"<<"a = "<<a<<" "<<"b = "<<b<<endl;
return 0;
}
swap.cc
#include "swap.h"
void swap(int &a,int &b)
{
int tmp=a;
a=b;
b=tmp;
}
swap.h
#ifndef SWAP_H__
#define SWAP_H__
void swap(int&,int&);
#endif
命令行输入
I后面的参数是目录,因为源代码中我使用的是#include"swap.h"
需要指定目录才能让编译器找到头文件
# g++ main.cc src/swap.cc -Iinclude -o main
-I指定头文件路径。编译得到一个名字为main的可执行程序,输入./main运行结果如下。
生成静(动)态库文件进行编译
库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。unix系统的静态库文件和动态库文件后缀分别是.a和.so;windows静态库文件就是.lib文件,动态库文件就是.dll文件。
两种库的区别在于静态库被调用时直接加载到内存,而动态库再是在需要的时候加载到内存,不使用的时候再从内存释放。
静态库
(以下案例参照第一幅树状图)
//静态库在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中
# cd Test/src
//第一步生成.o汇编文件,
# g++ -c swap.cc -I../include
//第二步生成静态库libswap.a,静态库的命名 libxxx.a
# ar rs libswap.a swap.o
//回到Test目录
# cd ..
//第三步链接生成可执行文件
#-l 指定链接时需要的库,刚刚生成的libswap.a,swap是库名
#-L 链接src目录下的库文件
#-I 链接include目录下的头文件
# g++ main.cc -lswap -Lsrc -Iinclude -o static_main
生成静态库文件后能够直接运行
动态库
# cd Test/src
//第一步生成.o文件
#-fpic 创建与地址无关的编译程序(加上就完事了)
# g++ -c swap.cc -fpic -I../include
//第二步生成动库文件libswap.so
#-shared 表示生成的是动态库
# g++ -shared -o libswap.so swap.o
# cd ..
//第三步链接生成可执行文件
# g++ main.cc -lswap -Lsrc -Iinclude -o dynamic_main
最后命令行输入来运行,指定库文件搜索路径
# LD_LIBRARY_PATH=src ./dynamic_main
Makefile
直接看陈皓写的把,我写的不好
https://blog.csdn.net/haoel/article/details/2886
CMake
基本语法
项目构建工具cmake是makefile的上层工具,目的是为了产生可移植的makefile,并简化自己动手写makefile时的巨大工作量。
和makefile类似,要创建一个CMakeLists.txt
#基本语法:指令(参数 参数;参数)
#参数之间是空格或分号
#指令用大小写都行
#cmake最低版本需求,不加入此行会受到警告信息
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
#添加编译参数
ADD_COMPILE_OPTIONS(-phread -wall)
ADD_SUBDIRECTORY(src)#指明本项目包含一个子目录src
#生成库文件
#${SRC},这个命令的是对SRC这个变量取值
ADD_LIBRARY ( Test ${SRC})
#把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
AUX_SOURCE_DIRECTORY(. SRC_LIST)
#编译SRC_LIST变量代表的所有源文件生成可执行程序 main
ADD_EXECUTABLE(main ${SRC_LIST})
#添加头文件搜索路径,相当于于指定g++编译器的参数-I
#dir是路径(绝对路径和相对路径都可)
INCLUDE_DIRECTORIES(dir);
#添加库文件的搜索路径,相当于g++的参数-L
LINK_DIRECTORIES(dir)
#指定项目名称
PROJECT(HELLO)
#定义src变量,值为hello1.c、hello2.c
SET(src hello1.c hello2.c)
#指明可执行文件 main需要连接一个名为Test的链接库
#类似g++ -l参数
TARGET_LINK_LIBRARIES( main Test )
编译流程
1、编写CMakeLists.txt
2、执行命令cmake生成一个makefile文件
3、执行命令make
两种构建方式
在正式开始写CMakeLists.txt之前,介绍一下两种构建方式
1、内部构建
cmake在当前目录会产生其他文件,而且这些文件我们不需要,就显得很杂乱,所以不推荐使用
2、外部构建(一般使用这个)
这个是通过mkdir 一个 build 目录,(名字自拟,常使用的是build),与内部构建不同的是,外部构建会把生成的文件都放在build目录下,所以推荐使用这个。
实例编译
单目录源文件内部构建编译
三步走战略:
第一步:编写CMakeLists.txt
如果用g++来编译:g++ HelloWorld.cc -o HelloWorld
#必须的这一步 设置可接受的最低版本号
#版本号的可以通过cmake --version命令查看
cmake_minimum_required(VERSION 3.0)
#设置项目名称
project(HELLOWORLD)
#项目名称应该要和add_executable的第一个参数名相同,大小写无所谓
#g++ HelloWorld.cc -o HelloWorld
add_executable(HelloWorld HelloWorld.cc)
第二步:执行cmake .
注意这个cmake后的点,表示CMakeLists.txt是在当前目录下
现在我们得到了一个我们需要的Makefile文件和其他我们不需要的东西,所以采用外部构建的方式是非常有必要的。
第三步
执行make
bingo,已经成功生成了一个HelloWorld可执行程序了。
多目录源文件外部构建编译
第一步:写CMakeLists.txt
如果用g++来编译:g++ main.cc src/swap.cc -Iinclude -o main
cmake_minimum_required(VERSION 3.0)
project(SWAP)
#g++ -Iinclude
//#include_directories(include),下面是绝对路径,这是相对路径,都是可以的
include_directories(${CMAKE_SOURCE_DIR}/include)
#g++ main.cc src/swap.cc -o main
add_executable(swap main.cc src/swap.cc)
第二步:cmake
mkdir build,在build目录下执行cmake(后面两个.),因为CMakeLists.txt在上一级目录。
第三步:make
基本的Cmake使用方法就介绍到这,可能以后会补充。