Verwendung von make für die plattformübergreifende Kompilierung

Lesezeit: 7 Minuten

Benutzer-Avatar
bph

Ich entwickle derzeit ein C-Projekt unter Linux und Win32. Das „Ergebnis“ ist eine gemeinsam genutzte Bibliothek, und die gesamte Entwicklung erfolgt unter Linux mit der GNU-Werkzeugkette. Ich verwende ein Makefile, um die gemeinsam genutzte Bibliothek zu kompilieren.

Hin und wieder muss ich eine .dll unter Win32 aus der gleichen Quelle bauen.

Ich habe MinGW auf der Win32-Box installiert, sodass ich make und get verwenden kann weit weniger Beschwerden vom Compiler (im Vergleich zu MSVC). Ich bin in einer Phase, in der der src-Code auf beiden Plattformen kompiliert wird

Aber das Linux-Makefile und das Win32-Makefile sind unterschiedlich. Ich bin gespannt, wie ich das am besten handhabe – sollte ich:

  1. habe 2 Makefiles, zB Makefile für Linux und Makefile.WIN32 und dann laufen lassen make -f Makefile.WIN32 auf der Windows-Box

  2. Sollte ich ein anderes Ziel in einem einzigen Makefile erstellen und so etwas tun wie make WIN32 auf der Windows-Box

  3. Soll ich auf make verzichten und CMake verwenden (ist der Saft den Druck für ein so einfaches Projekt wert, dh 1 gemeinsam genutzte Bibliothek)

Verwenden Sie eine einzelne Make-Datei und fügen Sie die Plattformspezifikationen ein Bedingungenz.B

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

DLL := libfoo$(DLLEXT)

lib : $(DLL)

  • Während dieser Ansatz wohl einige Probleme hat (nicht sehr modular, erneutes Ausführen der Feature-Erkennung auf jedem make Aufruf), denke ich nicht, dass sie für Ihren Anwendungsfall von Bedeutung sind; auch GNU make ist leistungsfähig genug, um darauf ein Konfigurationssystem aufzubauen (z. B. können Sie automatisch Makefile-Snippets für include und führen Sie beliebigen Code über aus $(shell)Diagnose erstellen über $(info) und $(error)…)

    – Christoph

    21. März 2012 um 10:13 Uhr


  • oreilly.com/catalog/make3/book/ch07.pdf In diesem Buch erfahren Sie, wie Sie portables Makefile schreiben.

    – zhanxw

    12. September 2013 um 4:40 Uhr

Benutzer-Avatar
oho

ich benutze UNAME := $(shell uname) in meinem Makefile um die Plattform (Linux oder MS-Windows) zu erkennen.

Ich stelle unten ein vollständiges Beispiel basierend auf make und gcc So erstellen Sie eine gemeinsam genutzte Bibliothek: *.so oder *.dll abhängig von der Plattform.

Das Beispiel ist einfach/einfach/dumm, um verständlicher zu sein 🙂

Benutzen make und gcc auf MS-Windows, Cygwin oder MinGW installiert werden kann.

Das Beispiel verwendet fünf Dateien:

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

Das 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

Der Quellcode

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";
}

Der Aufbau

Korrigieren Sie das Kopieren und Einfügen von Makefiles (Führende Leerzeichen durch Tabellierung ersetzen).

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

Das make Der Befehl ist auf beiden Plattformen gleich. Die angegebene Ausgabe ist für MS-Windows (unnötige Zeilen entfernt).

> 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

Der Lauf

Die Anwendung muss wissen, wo sich die gemeinsam genutzte Bibliothek befindet.

Unter MS-Windows besteht der einfache/grundlegende/dumme Weg darin, die Bibliothek zu kopieren, in der sich die Anwendung befindet:

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

Verwenden Sie unter Linux die LD_LIBRARY_PATH Umgebungsvariable:

> export LD_LIBRARY_PATH=lib

Die Ausführungsbefehlszeile und die Ausgabe sind auf beiden Plattformen gleich:

> app/app.exe
hello

Als jemand, der sowohl Autotools als auch CMake verwendet hat, würde ich empfehlen, CMake anstelle Ihrer eigenen Makefiles zu verwenden und Autotools zu verwenden. CMake hat so viele nützliche, einfach zu verwendende Vorteile, selbst wenn es sich um ein einfaches Projekt handelt. Zum Beispiel erstellt CMake ein NSIS-Installationsprogramm, verwaltet die Kompilierung der Produktion im Vergleich zur Debug-Kompilierung und verfügt über ein nettes Test-Framework. Der einzige Schlag, den ich hatte, war, dass es ziemlich schwierig war, echte Beispiele dafür zu finden, wie man es benutzt. So viel Open-Source-Software verwendet Autotools, dass reale Beispiele dafür leicht zu finden sind. Wenn Sie jedoch die CMake-Quelle herunterladen, finden Sie viele Beispiele im Beispielverzeichnis und im Testverzeichnis.

Mit anderen Worten, der Juice ist den Druck wert.

  • Links zu besagten Quellen?

    – Alex Gray

    6. Mai 2016 um 2:49 Uhr

Ich hatte vor ein paar Jahren ein ähnliches Problem und bin darauf gestoßen cm machen ist viel einfacher für die plattformübergreifende Kompilierung UND verwendet den Compiler, der für dieses System nativ ist. Die Syntax ist klarer und abstrahiert Details, die zum größten Teil unnötig sind (manchmal war das im Weg, aber normalerweise gab es einen Ausweg).

Als primären Rat empfehle ich die Verwendung von libtool, autoconf und automake; Sie machen die Cross-Kompilierung sehr einfach und viel einfacher als CMake.

Wenn Sie den handgefertigten Weg gehen, würde ich vorschlagen, mit anderen Zielen zu gehen. Das Umschalten zwischen Makefiles neigt dazu, ansonsten offensichtliche Fehler in Makefiles zu verbergen, zB doppelt verwendete Objekte mit unterschiedlichen Regeln. Beispiel: Das Objekt foo.o wird für das DLL-Target und für das .so-Target kompiliert, aber mit unterschiedlichen Flags. Wenn jemand Makefiles wechselt, wird die vorhandene .o-Datei mit falschen Flags verwendet, wodurch der Build beschädigt wird. Wenn Sie ein Makefile verwenden, wird dies durch Regelkonflikte deutlich.

  • Autotools sind großartig, wenn sie funktionieren, aber das ist nicht immer der Fall; Zum Beispiel habe ich Git nur dazu gebracht, auf MinGW aufzubauen, indem ich explizite Konfigurationsargumente für bereitgestellt habe makeund nicht über das automatisierte System …

    – Christoph

    20. März 2012 um 21:55 Uhr


Wenn Sie bereit sind, MSYS2 unter Windows zu verwenden, können Sie es möglicherweise zum Laufen bringen ohne irgendwelche Änderungen vorzunehmen im Vergleich zu Ihrem für Linux geschriebenen Code. Dies gilt sowohl für Ihren C/C++-Quellcode als auch für Ihr Makefile.(!)

Ich habe ausschließlich Code für Linux entwickelt. Als ich versuchte, es in einem MSYS2-Terminal auszuführen, stellte sich heraus, dass der Code einwandfrei funktionierte und eine ausführbare Windows-Binärdatei erzeugte. Ich war positiv überrascht.

Sie müssen natürlich wissen, wie MSYS2 installiert und verwendet wird. Um beispielsweise make und g++ zu installieren, führen Sie in einem MSYS2-Terminal die folgenden Befehle aus:

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

Wenn Sie herausfinden möchten, wo in Windows g++ installiert wurde, können Sie ausführen
where g++ im MSYS2-Terminal.

Verweise:
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

  • Autotools sind großartig, wenn sie funktionieren, aber das ist nicht immer der Fall; Zum Beispiel habe ich Git nur dazu gebracht, auf MinGW aufzubauen, indem ich explizite Konfigurationsargumente für bereitgestellt habe makeund nicht über das automatisierte System …

    – Christoph

    20. März 2012 um 21:55 Uhr


1383220cookie-checkVerwendung von make für die plattformübergreifende Kompilierung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy