使用make进行跨平台编译

我目前正在Linux和Win32下开发一个C项目。 ‘deliverrable’是一个共享库,所有开发都是在Linux下使用GNU工具链完成的。 我正在使用Makefile来编译共享库。

我不得不在同一个src下在Win32下构建一个.dll。

我已经在Win32盒子上安装了MinGW,这样我就可以使用make并从编译器中获得更少的投诉(与MSVC相比)。 我正处于src代码在两个平台上编译的阶段

但是Linux Makefile和Win32 Makefile是不同的。 我很好奇如何最好地处理这个 – 我应该:

  1. 有2个makefile,例如Makefile for linux和Makefile.WIN32然后在Windows框上运行make -f Makefile.WIN32

  2. 我应该在单个Makefile中创建一个不同的目标,并在Windows框中执行类似make WIN32的操作

  3. 我应该放弃制作并使用CMake(对于这样一个简单的项目来说,果汁值得挤压,即1个共享库)

使用单个make文件并将特定于平台的内容放在条件中 ,例如

 ifeq ($(OS),Windows_NT) DLLEXT := .dll else DLLEXT := .so endif DLL := libfoo$(DLLEXT) lib : $(DLL) 

我在Makefile使用UNAME := $(shell uname)来检测平台(Linux或MS-Windows)。

我在下面提供了一个基于makegcc的完整示例来构建一个共享库: *.so*.dll具体取决于平台。

这个例子是基本的/简单的/愚蠢的更容易理解:-)

要在MS-Windows上使用makegcc ,可以安装Cygwin或MinGW 。

该示例使用五个文件:

  ├── app │ └── Makefile │ └── main.c └── lib └── Makefile └── hello.h └── hello.c 

Makefiles

app/Makefile

 app.exe: main.o gcc -o $@ $^ -L../lib -lhello # '-o $@' => output file => $@ = the target file (app.exe) # ' $^' => no options => Link all depended files # => $^ = main.o and other if any # '-L../lib' => look for libraries in directory ../lib # '-lhello => use shared library hello (libhello.so or hello.dll) %.o: %.c gcc -o $@ -c $< -I ../lib # '-o $@' => output file => $@ = the target file (main.o) # '-c $<' => COMPILE the first depended file (main.cpp) # '-I ../lib' => look for headers (*.h) in directory ../lib clean: rm -f *.o *.so *.dll *.exe 

lib/Makefile

 UNAME := $(shell uname) ifeq ($(UNAME), Linux) TARGET = libhello.so else TARGET = hello.dll endif $(TARGET): hello.o gcc -o $@ $^ -shared # '-o $@' => output file => $@ = libhello.so or hello.dll # ' $^' => no options => Link all depended files => $^ = hello.o # '-shared' => generate shared library %.o: %.c gcc -o $@ -c $< -fPIC # '-o $@' => output file => $@ = the target file (main.o) # '-c $<' => compile the first depended file (main.cpp) # '-fPIC' => Position-Independent Code (required for shared lib) clean: rm -f *.o *.so *.dll *.exe 

源代码

app/main.c

 #include "hello.h" //hello() #include  //puts() int main() { const char* str = hello(); puts(str); } 

lib/hello.h

 #ifndef __HELLO_H__ #define __HELLO_H__ const char* hello(); #endif 

lib/hello.c

 #include "hello.h" const char* hello() { return "hello"; } 

构建

修复Makefiles的复制粘贴(通过制表替换前导空格)。

 > sed -i 's/^ */\t/' */Makefile 

make命令在两个平台上都是相同的。 给定的输出用于MS-Windows(删除了不必要的行)。

 > cd lib > make clean > make gcc -o hello.o -c hello.c -fPIC gcc -o hello.dll hello.o -shared > cd ../app > make clean > make gcc -o main.o -c main.c -I ../lib gcc -o app.exe main.o -L../lib -lhello 

运行

应用程序需要知道共享库的位置。

在MS-Windows上,简单/基本/愚蠢的方法是复制应用程序所在的库:

 > cp -v lib/hello.dll app `lib/hello.dll' -> `app/hello.dll' 

在Linux上,使用LD_LIBRARY_PATH环境变量:

 > export LD_LIBRARY_PATH=lib 

两个平台上的run命令行和输出相同:

 > app/app.exe hello 

几年前我遇到过类似的问题,发现cmake更容易进行跨平台编译,并且会使用该系统的任何编译器。 语法更清晰,抽象大部分都不需要的细节(有时会妨碍,但通常有一种解决方法)

作为使用过autotools和CMake的人,我建议使用CMake滚动你自己的Makefile并使用autotools。 即使是一个简单的项目,CMake也有许多有用且易于使用的好处。 例如,CMake将创建一个NSIS安装程序,管理生产与调试编译,并有一个很好的测试框架。 我遇到的一个问题是,很难找到如何使用它的真实例子。 这么多开源软件使用自动工具,很容易找到它的真实世界的例子。 但是,如果您下载CMake源,那么Example目录和Test目录中有很多示例。

换句话说,Juice值得挤压。

作为主要建议,我建议使用libtool,autoconf和automake; 它们使交叉编译非常容易,并且比CMake更容易。

如果你要进行手工制作的路线,我建议选择不同的目标。 在makefile之间切换往往会隐藏Makefile中明显的错误,例如,具有不同规则的重复使用的对象。 示例:对象foo.o是针对DLL目标和.so目标编译的,但具有不同的标志。 如果有人切换Makefile,则使用带有错误标志的现有.o文件,从而破坏构建。 如果您使用的是一个Makefile,这将通过规则冲突变得明显。