Using make for cross platform compilation

前端 未结 6 1763
野趣味
野趣味 2021-02-05 05:03

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 u

相关标签:
6条回答
  • 2021-02-05 05:26

    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)

    0 讨论(0)
  • 2021-02-05 05:36

    I use UNAME := $(shell uname) within my Makefile to detect the platform (Linux or 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.

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

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

    The example uses five files:

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

    The 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
    

    The source code

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

    The build

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

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

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

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

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

    On Linux, use the LD_LIBRARY_PATH environment variable:

    > export LD_LIBRARY_PATH=lib
    

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

    > app/app.exe
    hello
    
    0 讨论(0)
  • 2021-02-05 05:41

    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.

    In other words, the Juice is worth the squeeze.

    0 讨论(0)
  • 2021-02-05 05:41

    As a primary advice, I suggest using libtool, autoconf and automake; they make cross-compilation very easy, and much easier than 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.

    0 讨论(0)
  • 2021-02-05 05:43

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

    ifeq ($(OS),Windows_NT)
        DLLEXT := .dll
    else
        DLLEXT := .so
    endif
    
    DLL := libfoo$(DLLEXT)
    
    lib : $(DLL)
    
    0 讨论(0)
  • 2021-02-05 05:46

    If you are willing to use MSYS2 on Windows you might get it to run without making any changes at all compared to your code written for Linux. This goes for your C/C++ source code as well as for your makefile.(!)

    I have been developing code for Linux exclusively. When I tried running it inside an MSYS2 terminal, the code turned out to work just fine, and produced a Windows binary executable. I was positively surprised.

    You will need to know how to install and use MSYS2, of course. For example, to install make and g++, in an MSYS2 terminal run the commands:

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

    If you want to find out where in Windows g++ has been installed, you can run where g++ in the MSYS2 terminal.

    References:
    https://www.msys2.org/wiki/MSYS2-installation/
    https://github.com/msys2/MSYS2-packages/issues/293

    0 讨论(0)
提交回复
热议问题