使用make进行跨平台编译

时间:2012-03-20 16:41:50

标签: c makefile cross-platform

我目前正在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个共享库)

6 个答案:

答案 0 :(得分:20)

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

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

DLL := libfoo$(DLLEXT)

lib : $(DLL)

答案 1 :(得分:12)

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

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

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

要在MS-Windows上使用makegcc,可以安装CygwinMinGW

该示例使用五个文件:

 ├── 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 <stdio.h> //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

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

> app/app.exe
hello

答案 2 :(得分:4)

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

答案 3 :(得分:4)

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

换句话说,Juice值得挤压。

答案 4 :(得分:3)

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

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

答案 5 :(得分:0)

如果您愿意在Windows上使用MSYS2,则可以使其不运行而运行 与您为Linux编写的代码相比,根本没有任何改变。 这既适合您的C / C ++源代码,也适合您的makefile。(!)

我一直在专门为Linux开发代码。当我尝试运行它 在MSYS2终端中,代码可以正常工作,并且 产生了Windows二进制可执行文件。我很惊讶。

当然,您将需要知道如何安装和使用MSYS2。例如, 要安装make和g ++,请在MSYS2终端中运行以下命令:

yes | pacman -Syu msys/make
yes | pacman -Syu gcc

如果要了解Windows g ++的安装位置,可以运行 where g++在MSYS2终端中。

参考文献:
https://www.msys2.org/wiki/MSYS2-installation/
https://github.com/msys2/MSYS2-packages/issues/293
https://superuser.com/questions/21067/windows-equivalent-of-whereis#39309