makefiles make how clean c makefile cross-platform

how - Usando make para compilación multiplataforma



makefile executable linux (5)

Como alguien que ha usado tanto autotools como CMake, recomendaría usar CMake sobre rodar tus propios Makefiles y usar autotools. CMake tiene muchos beneficios útiles y fáciles de usar, incluso si se trata de un proyecto simple. Por ejemplo, CMake creará un instalador de NSIS, administrará la producción frente a la compilación de depuración y tendrá un marco de prueba agradable. El único golpe que tuve fue que era un poco difícil encontrar ejemplos reales de cómo usarlo. Tanto el software de código abierto utiliza autotools que los ejemplos del mundo real son fáciles de encontrar. Sin embargo, si descarga la fuente de CMake, hay muchos ejemplos en el directorio de ejemplo y el directorio de prueba.

En otras palabras, el jugo vale la pena apretarlo.

Actualmente estoy desarrollando un proyecto de C en Linux y Win32. El ''entregable'' es una biblioteca compartida, y todo el desarrollo se realiza bajo Linux con la cadena de herramientas GNU. Estoy utilizando un Makefile para compilar la biblioteca compartida.

De vez en cuando tengo que construir un .dll bajo Win32 desde el mismo src.

He instalado MinGW en la caja de Win32, de modo que puedo usar make y obtener muchas menos quejas del compilador (en comparación con MSVC). Estoy en una etapa donde el código src se compila en ambas plataformas

Pero el Makefile de Linux y el Makefile de Win32 son diferentes. Tengo curiosidad por saber cómo manejar mejor esto: debería:

  1. tiene 2 makefiles, por ejemplo, Makefile para linux y Makefile.WIN32 y luego ejecuta make -f Makefile.WIN32 en el cuadro de Windows

  2. Debería hacer un objetivo diferente en un solo Makefile y hacer algo como make WIN32 en el cuadro de Windows

  3. ¿Debería tirar y usar CMake (vale la pena exprimirlo para un proyecto tan simple, es decir, una biblioteca compartida)?


Como consejo principal, sugiero usar libtool, autoconf y automake; Hacen la compilación cruzada muy fácil y mucho más fácil que CMake.

Si va por la ruta hecha a mano, sugeriría ir con diferentes objetivos. El cambio entre makefiles tiende a ocultar errores obvios en Makefiles, por ejemplo, objetos usados ​​de forma duplicada con diferentes reglas. Ejemplo: El objeto foo.o se compila para el destino de DLL y para el destino .so, pero con indicadores diferentes. Si alguien cambia Makefiles, se usa el archivo .o existente con banderas incorrectas, rompiendo la construcción. Si está utilizando un Makefile, esto se volverá obvio a través de los conflictos de reglas.


Tuve un problema similar hace unos años, y descubrí que cmake es mucho más fácil para la compilación multiplataforma Y utilizará cualquier compilador nativo para ese sistema. La sintaxis es más clara y abstrae los detalles que son innecesarios en su mayor parte (a veces eso se interpuso en el camino, pero generalmente había una forma de evitarlo)


Use un solo archivo de creación y ponga los específicos de la plataforma en conditionals , por ejemplo,

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


Uso UNAME := $(shell uname) dentro de mi Makefile para detectar la plataforma (Linux o MS-Windows).

Proporciono a continuación un ejemplo completo basado en make y gcc para construir una biblioteca compartida: *.so o *.dll según la plataforma.

El ejemplo es básico / simple / estúpido para ser más comprensible :-)

Para usar make y gcc en MS-Windows, Cygwin o MinGW se pueden instalar.

El ejemplo usa cinco archivos:

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

Los 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

El código fuente

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

La construcción

Corrija la copia y pegado de Makefiles (reemplace los espacios iniciales por tabulación).

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

El comando make es el mismo en ambas plataformas. La salida dada es para MS-Windows (líneas innecesarias eliminadas).

> 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

La carrera

La aplicación requiere saber dónde está la biblioteca compartida.

En MS-Windows, la forma simple / básica / estúpida es copiar la biblioteca donde está la aplicación:

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

En Linux, use la LD_LIBRARY_PATH entorno LD_LIBRARY_PATH :

> export LD_LIBRARY_PATH=lib

La línea de comando de ejecución y la salida son las mismas en ambas plataformas:

> app/app.exe hello