c++跨平台技术学习(二)--使用跨平台的Make系统
make主要用在代码移植性上。跨平台管理编译工作有好几种方法,每种的核心都是一个叫make的程序,这是一个跨平台的工具。
Make
假如你有一个程序叫做bar,它由bar.cpp和main.cpp两个C++源文件以及一个bar.h头文件组成
main.cpp
#include "bar.h" |
bar.h
#pragma once |
bar.cpp
#include<stdlib.h> |
bar对象维护了一个整数m_bar.m_bar的值由SetBar()决定,而PutBar()函数则把m_bar的值存到环境变量BAR里。
从创建一个简单脚本build.sh开始,把它编译链接为一个bar应用程序
#! /bin/sh |
随后执行
sh build.sh |
make工具按照一定的依赖规则来执行一组命令,以获得需要的目标或结果。上面例子中,目标就是可执行文件bar,它依赖于源文件bar.cpp和main.cpp,而用来生成可执行文件的命令是
g++ -o bar bar.cpp main.cpp |
make要求在一个文件里指定目标,依赖关系和命令,通常这个文件的名字是Makefile,下面这个makefile同样可以编译我们的例子
bar:bar.cpp main.cpp |
有了Makefile之后,只需要键入下列命令
make |
然后make就会为我们生成bar程序
make如何处理shell脚本带来的问题:
- make没彻底消除可移植性,在windows上,make并不像linux活mac上那样是原生应用程序.
- makefile并没有解决指定不同编译器编译项目的问题。
- 命令行参数依然是硬编码
make只会在源码的修改时间比可执行文件的修改时间万,才重新编译bar
如何改进呢,重写makefile如下
bar:bar.o main.o |
上面的makefile通过引入两个新目标bar.o和main.o解决了依赖性的问题。现在依赖关系有了明确的目标,例如当bar.cpp和bar.h发生修改时,bar.o应该重新编译。bar自己的依赖关系也发生了变化,它不在依赖于源文件,而是依赖于目标文件。所以touch文件main.cpp后再执行make时,会得到以下结果
touch main.cpp |
注意到make只重新编译了目标main.o和bar,但是编译器和命令行参数仍旧是硬编码。这两个问题都可以用macro来解决
OBJS=bar.o main.o |
如果你注意到所有的.o文件其实都只依赖于对应的.cpp文件和bar.h的话,我们可以进一步改进Makefile,通过额外的make机制如模式规则(pattern rules),Makefile可以简化为:
OBJS=bar.o main.o |
问题依然存在,把-g 提取出来放到CXXFLAGS里确实是一大进步,但是依然是Makefile里的硬编码,what’s more terrible,它和编译器脱离开来了,如果CXX不是使用g++,那么-g可能会在别的编译器上有完全不同的意思
未完待续……