使用make进行跨平台编译

时间:2021-09-02 12:28:35

I am currently developing a C project under Linux and Win32. The 'deliverable' is a shared library, and all the development is done under Linux with the GNU tool chain. I am using a Makefile to compile the shared library.

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

Every now and then I have to build a .dll under Win32 from the same src.

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

I've installed MinGW on the Win32 box such that I can use make and get far fewer complaints from the compiler (in comparison to MSVC). I'm at a stage where the src code compiles on both platforms

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

But the Linux Makefile and Win32 Makefile are different. I'm curious as how to best handle this - should I:

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

  1. have 2 makefiles, e.g. Makefile for linux and Makefile.WIN32 and then run make -f Makefile.WIN32 on the Windows box

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

  2. Should I make a different target in a single Makefile and do something like make WIN32 on the Windows box

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

  3. Should I ditch make and use CMake (is the juice worth the squeeze for such a simple project, i.e. 1 shared library)

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

5 个解决方案

#1


17  

Use a single make file and put the platform-specifics in conditionals, eg

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

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

DLL := libfoo$(DLLEXT)

lib : $(DLL)

#2


12  

I use UNAME := $(shell uname) within my Makefile to detect the platform (Linux or MS-Windows).

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

I provide below a complete example based on make and gcc to build a shared library: *.so or *.dll depending on the platform.

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

The example is basic/simple/stupid to be more understandable :-)

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

To use make and gcc on MS-Windows, Cygwin or MinGW can be installed.

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

The example uses five files:

该示例使用五个文件:

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

The Makefiles

app/Makefile

应用程序/ 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

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

The source code

app/main.c

应用程序/ main.c中

#include "hello.h" //hello()
#include <stdio.h> //puts()

int main()
{
    const char* str = hello();
    puts(str);
}

lib/hello.h

LIB / hello.h

#ifndef __HELLO_H__
#define __HELLO_H__

const char* hello();

#endif

lib/hello.c

LIB / hello.c中

#include "hello.h"

const char* hello()
{
    return "hello";
}

The build

Fix the copy-paste of Makefiles (replace leading spaces by tabulation).

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

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

The make command is the same on both platforms. The given output is for MS-Windows (unnecessary lines removed).

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

The run

The application requires to know where is the shared library.

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

On MS-Windows, the simple/basic/stupid way is to copy the library where the application is:

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

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

On Linux, use the LD_LIBRARY_PATH environment variable:

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

> export LD_LIBRARY_PATH=lib

The run command line and output are the same on both platforms:

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

> app/app.exe
hello

#3


4  

I had a similar issue a few years back, and found that cmake is much easier for cross-platform compilation AND will use whatever compiler is native for that system. Syntax is clearer and abstracts details that are unnecessary for the most part (sometimes that got in the way, but usually there was a way around it)

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

#4


4  

As somebody who has used both autotools and CMake, I would recommend using CMake over rolling your own Makefiles and using autotools. CMake has so many useful, easy to use benefits, even if it is a simple project. For example, CMake will create an NSIS installer, manage production vs. debug compilation and has a nice testing framework. The one knock I had was that it was kind of hard to find real examples of how to use it. So much open source software uses autotools that realworld examples for it are easy to find. However, if you download the CMake source, there are lots of examples in the Example directory and Test directory.

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

In other words, the Juice is worth the squeeze.

换句话说,Juice值得挤压。

#5


3  

As a primary advice, I suggest using libtool, autoconf and automake; they make cross-compilation very easy, and much easier than CMake.

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

If you are going the hand-crafted route, I would suggest going with different targets. Switching between makefiles tends to hide otherwise obvious errors in Makefiles, e.g. duplicately used objects with different rules. Example: The object foo.o is compiled for the DLL target and for the .so target, but with different flags. If someone switches Makefiles, the existing .o file with wrong flags is used, breaking the build. If you are using one Makefile, this will become obvious through rule conflicts.

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

#1


17  

Use a single make file and put the platform-specifics in conditionals, eg

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

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

DLL := libfoo$(DLLEXT)

lib : $(DLL)

#2


12  

I use UNAME := $(shell uname) within my Makefile to detect the platform (Linux or MS-Windows).

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

I provide below a complete example based on make and gcc to build a shared library: *.so or *.dll depending on the platform.

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

The example is basic/simple/stupid to be more understandable :-)

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

To use make and gcc on MS-Windows, Cygwin or MinGW can be installed.

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

The example uses five files:

该示例使用五个文件:

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

The Makefiles

app/Makefile

应用程序/ 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

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

The source code

app/main.c

应用程序/ main.c中

#include "hello.h" //hello()
#include <stdio.h> //puts()

int main()
{
    const char* str = hello();
    puts(str);
}

lib/hello.h

LIB / hello.h

#ifndef __HELLO_H__
#define __HELLO_H__

const char* hello();

#endif

lib/hello.c

LIB / hello.c中

#include "hello.h"

const char* hello()
{
    return "hello";
}

The build

Fix the copy-paste of Makefiles (replace leading spaces by tabulation).

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

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

The make command is the same on both platforms. The given output is for MS-Windows (unnecessary lines removed).

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

The run

The application requires to know where is the shared library.

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

On MS-Windows, the simple/basic/stupid way is to copy the library where the application is:

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

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

On Linux, use the LD_LIBRARY_PATH environment variable:

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

> export LD_LIBRARY_PATH=lib

The run command line and output are the same on both platforms:

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

> app/app.exe
hello

#3


4  

I had a similar issue a few years back, and found that cmake is much easier for cross-platform compilation AND will use whatever compiler is native for that system. Syntax is clearer and abstracts details that are unnecessary for the most part (sometimes that got in the way, but usually there was a way around it)

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

#4


4  

As somebody who has used both autotools and CMake, I would recommend using CMake over rolling your own Makefiles and using autotools. CMake has so many useful, easy to use benefits, even if it is a simple project. For example, CMake will create an NSIS installer, manage production vs. debug compilation and has a nice testing framework. The one knock I had was that it was kind of hard to find real examples of how to use it. So much open source software uses autotools that realworld examples for it are easy to find. However, if you download the CMake source, there are lots of examples in the Example directory and Test directory.

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

In other words, the Juice is worth the squeeze.

换句话说,Juice值得挤压。

#5


3  

As a primary advice, I suggest using libtool, autoconf and automake; they make cross-compilation very easy, and much easier than CMake.

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

If you are going the hand-crafted route, I would suggest going with different targets. Switching between makefiles tends to hide otherwise obvious errors in Makefiles, e.g. duplicately used objects with different rules. Example: The object foo.o is compiled for the DLL target and for the .so target, but with different flags. If someone switches Makefiles, the existing .o file with wrong flags is used, breaking the build. If you are using one Makefile, this will become obvious through rule conflicts.

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