进行简单的替换。
//程序名称:test.cpp
#include
#define hello "六六六"
int main(){
std::cout<
此命令将 test.cpp文件进行预编译,编译的结果放在了test.txt文件中。
如果没有 ">test.txt" 命令,则预编译的结果会直接打印在屏幕上。
linux中默认生成.o文件;windows中生成.exe文件。
把多个目标文件链接成可执行文件
//程序名称:main.c #include
#include "add.h" #include "sub.h" int main(){ int a,b; printf("请输入a和b:"); scanf("%d%d",&a,&b); printf("%d + %d = %d\n",a,b,add(a,b)); printf("%d - %d = %d\n",a,b,sub(a,b)); return 0; } //程序名称:add.h int add(int,int);
//程序名称:add.c int add(int a,int b){ return a+b; }
//程序名称:sub.h int sub(int,int);
//程序名称:sub.c int sub(int a,int b){ return a-b; }
gcc *.o -o test.exe
//将所有.o文件链接为一个.exe文件
/*
目的:依赖
通过依赖生成目的的语句
*/
demo.exe:main.o add.o sub.o #顶头书写;要生成的文件:依赖的文件
gcc main.o add.o sub.o -o demo.exe #空一个tab键的位置(不能是空格);书写编译语言
main.o:main.c
gcc -c main.c -o main.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
clean:
rm -f *.o *exe #删除所有.o和.exe文件
#将以上的makefile文件进行优化
/*
$@————代表“目的”
* ————代表任意个任意字符
*/
demo.exe:main.o add.o sub.o
gcc *.o -o $@
%.o:%.c #这两句按照第一行main.o add.o sub.o的顺序依次执行
gcc -c %< -o $@ #更改时,只用更改main.o add.o sub.o这部分依赖的顺序就可以了
clean:
rm -f *.o *exe
是一个高级编译配置工具。当多个人使用不同的编程语言开发同一个项目时就要用到CMake命令,最终输出一个可执行文件或者共享库(dll,so等)。
所有操作都是通过遍历CMakeList.txt来完成的。官网,各个版本的下载地址
(PS:建议直接安装最新版本,删除旧版本很费劲。推荐一个安装方案,我卸载的最后一步是which cmake查找路径后删除)
在Linux上安装cmake的命令(需要用root权限执行)
步骤1:写一个helloworld程序
//程序名称:main.cpp
#include
int main(){
std::cout<<"helloworld"<
步骤2:写CMakeLists.txt
//文件名称:CMakeLists.txt,必须严格区分大小写,且名称只能是这个
PROJECT (HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
步骤3:执行CMakeLists.txt文件
当CMakeLists.txt文件存放在当前路径时,使用cmake . 命令(cmake .. 命令表示CMakeList.txt文件存放在上一级目录中),表示执行当前路径的CMakeLists.txt文件,执行结束后,生成一个Makefile文件,用make执行该命令即可
PROJECT关键字
指定工程名字和支持的语言(语言用大写),默认支持所有语言。
PROJECT (HELLO C CXX JAVA)支持C,C++,Java
我们通常把公用的自定义函数和类从主程序中分离出来,函数和类的声明在头文件中,定义在程序文件中,主程序中要包含头文件,编译时要和程序文件一起编译。
//程序名:public.h,公共功能函数声明的头文件,用于测试静态和动态链接
#ifndef PUBLIC_H
#define PUBLIC_H 1
#include
void func(); // 自定义函数的声明
#endif
//程序名:public.cpp,公共功能函数定义的程序文件,用于测试静态和动态链接
#include "public.h" // 包含自定义函数声明的头文件
void func() // 自定义函数的实现
{
printf("我心匪石,不可转也。我心匪席,不可卷也。威仪棣棣,不可选也。\n");
//printf("生活美好如鲜花,不懂享受是傻瓜;\n");
//printf("傻呀傻呀傻呀傻,比不上小鸟和乌鸦。\n");
//printf("芳草地啊美如画,谁要不去是傻瓜;\n");
//printf("我是一只傻傻鸟,独在枯枝丫上趴。\n");
}
//程序名:book265.cpp,此程序用于测试静态和动态链接
#include "public.h" // 把public.h头文件包含进来
int main()
{
func();
}
公用函数库的程序文件public.cpp程序文件是源代码,对任何程序员是可见的,没有安全性可言。
把公共的程序文件编译成库文件,库文件是一种可执行代码的二进制形式,可以与其它的源程序一起编译,也可以被操作系统载入内存执行。
主程序文件与静态库一起编译,把主程序与主程序中用到的库函数一起整合进了目标文件。
优点:
在编译后的可执行程序可以独立运行——删去.a文件,则可执行程序正常运行
不需要像动态库那样有动态加载和识别函数地址的开销,也就是说采用静态链接编译的可执行程序运行更快
缺点:
1)静态链接生成的可执行程序比动态链接生成的大很多,运行时占用的内存也更多。
2)库文件的更新不会反映到可执行程序中,可执行程序需要重新编译。
静态库命名方式:“libxxx.a”,库名前加”lib”,后缀用”.a”,“xxx”为静态库名
把程序文件public.cpp编译成静态库的指令(自动生成libpublic.a文件;没有public.h文件,则该命令报错):
方法一:直接把调用者源代码和静态库文件名一起编译
方法二:采用L参数指定静态库文件的目录,-l参数指定静态库名
注意事项:
1、指定多个静态库文件的目录:“-L/目录1 -L目录2 -L目录3”
2、链接库的文件名是libpublic.a,但链接库名是”public”
3、指定多个静态库,用法是“-l库名1 -l库名2 -l库名3”
动态库在程序运行时才被载入,因此在程序运行时还需要指定动态库的目录。
优点:
1)相对于静态库,动态库在时候更新(修复bug,增加新的功能)不需要重新编译。
2)全部的可执行程序共享动态库的代码,运行时占用的内存空间更少。
缺点:
1)使可执行程序在不同平台上移植变得更复杂,因为它需要为每每个不同的平台提供相应平台的共享库——删去.so文件,则可执行程序报错
2)增加可执行程序运行时的时间和空间开销,因为应用程序需要在运行过程中查找依赖的库函数,并加载到内存中。
动态库的命名方式:“libxxx.so”,库名前加“lib”,后缀变为“.so” “xxx”为动态库名。
把程序文件public.cpp编译成动态库的指令(自动生成libpublic.so文件;没有public.h文件,则该命令报错):
如果在动态库文件和静态库文件同时存在,优先使用动态库编译。除非用-static参数指定链接静态库。
动态函数库并没有整合进程序,所以程序的运行环境必须提供动态库路径。Linux系统中采用LD_LIBRARY_PATH环境变量指定动态库文件的目录,设置命令如下:
注意事项:
指定多个动态库文件的目录:“export LD_LIBRARY_PATH=目录1:目录2:目录3:.”,目录之间用半角的冒号分隔,最后的圆点指当前目录