web-dev-qa-db-ja.com

クロスプラットフォームコンパイルにmakeを使用する

私は現在、LinuxとWin32でCプロジェクトを開発しています。 'deliverable'は共有ライブラリであり、すべての開発はLinuxでGNUツールチェーンを使用して行われます。Makefileを使用して共有ライブラリをコンパイルしています。

時々、同じsrcからWin32の下に.dllをビルドする必要があります。

私はWin32ボックスにMinGWをインストールして、makeを使用して取得できるようにしましたfarコンパイラからの苦情が少なくなりました(MSVCと比較して)。私はsrcコードが両方のプラットフォームでコンパイルされる段階にあります

ただし、LinuxMakefileとWin32Makefileは異なります。私はこれをどのように最適に処理するかについて興味があります-私は:

  1. 2つのメイクファイルがあります。 Linux用のMakefileとMakefile.WIN32を実行し、Windowsボックスでmake -f Makefile.WIN32を実行します。

  2. 1つのMakefileで別のターゲットを作成し、Windowsボックスでmake WIN32のようなことを行う必要があります

  3. CMakeを捨てて使用する必要があります(このような単純なプロジェクト、つまり1つの共有ライブラリの場合は絞る価値のあるジュースです)

21
bph

単一のmakeファイルを使用し、プラットフォーム固有のものを 条件付き に配置します。例:

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

DLL := libfoo$(DLLEXT)

lib : $(DLL)
23
Christoph

Makefile内でUNAME := $(Shell uname)を使用して、プラットフォーム(LinuxまたはMS-Windows)を検出します。

共有ライブラリを構築するためのmakegccに基づく完全な例を以下に示します:プラットフォームに応じて*.soまたは*.dll

例は、より理解しやすいように基本的/単純/愚かです:-)

MS-Windowsでmakeおよびgccを使用するには、 Cygwin または MinGW をインストールできます。

この例では、次の5つのファイルを使用しています。

 ├── 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
12
olibre

私は数年前に同様の問題を抱えていましたが、 cmake はクロスプラットフォームのコンパイルの方がはるかに簡単であり、そのシステムにネイティブなコンパイラを使用することがわかりました。構文はより明確で、ほとんどの部分で不要な詳細を抽象化します(邪魔になることもありますが、通常は回避する方法がありました)

5

AutotoolsとCMakeの両方を使用したことがある人として、独自のMakefileをロールしてautotoolsを使用するよりもCMakeを使用することをお勧めします。 CMakeには、単純なプロジェクトであっても、非常に多くの便利で使いやすい利点があります。たとえば、CMakeはNSISインストーラーを作成し、本番環境とデバッグコンパイルを管理し、優れたテストフレームワークを備えています。私が持っていた1つのノックは、それを使用する方法の実際の例を見つけるのがちょっと難しいということでした。非常に多くのオープンソースソフトウェアがautotoolsを使用しているため、実際の例を簡単に見つけることができます。ただし、CMakeソースをダウンロードすると、ExampleディレクトリとTestディレクトリに多くの例があります。

言い換えれば、ジュースは絞る価値があります。

5
ssgriffonuser

主なアドバイスとして、libtool、autoconf、automakeを使用することをお勧めします。クロスコンパイルが非常に簡単になり、CMakeよりもはるかに簡単になります。

手作りのルートを利用する場合は、別のターゲットを使用することをお勧めします。 makefileを切り替えると、Makefileの明らかなエラーが隠される傾向があります。異なるルールで重複して使用されたオブジェクト。例:オブジェクトfoo.oは、DLLターゲットと.soターゲット用にコンパイルされますが、フラグが異なります。誰かがMakefileを切り替えると、間違ったフラグを持つ既存の.oファイルが使用されます。ビルドを壊します。1つのMakefileを使用している場合、これはルールの競合によって明らかになります。

3
thiton