我目前正在Linux和Win32下开发一个C项目。 'deliverrable'是一个共享库,所有开发都是在Linux下使用GNU工具链完成的。我正在使用Makefile来编译共享库。
我不得不在同一个src下在Win32下构建一个.dll。
我在Win32盒子上安装了MinGW,这样我就可以使用make并从编译器中获得远更少的投诉(与MSVC相比)。我正处于src代码在两个平台上编译的阶段
但是Linux Makefile和Win32 Makefile是不同的。我很好奇如何最好地处理这个 - 我应该:
有2个makefile,例如Makefile for linux和Makefile.WIN32然后在Windows框上运行make -f Makefile.WIN32
我应该在单个Makefile中创建不同的目标,并在Windows框中执行类似make WIN32
的操作
我应该放弃制作并使用CMake(对于这样一个简单的项目来说,这是一个值得挤压的果汁,即1个共享库)
答案 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)。
我在下面提供了基于make
和gcc
的完整示例,以构建共享库:*.so
或*.dll
,具体取决于平台。
这个例子基本/简单/愚蠢更容易理解:-)
要在MS-Windows上使用make
和gcc
,可以安装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 <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