Quantcast
Channel: OS detecting makefile - Stack Overflow
Viewing all articles
Browse latest Browse all 15

Answer by oHo for OS detecting makefile

$
0
0

Detect the operating system using two simple tricks:

  • First the environment variable OS
  • Then the uname command
ifeq ($(OS),Windows_NT)     # is Windows_NT on XP, 2000, 7, Vista, 10...    detected_OS := Windowselse    detected_OS := $(shell uname)  # same as "uname -s"endif

Or a more safe way, if not on Windows and uname unavailable:

ifeq ($(OS),Windows_NT)     detected_OS := Windowselse    detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown')endif

Ken Jackson proposes an interesting alternative if you want to distinguish Cygwin/MinGW/MSYS/Windows. See his answer that looks like that:

ifeq '$(findstring ;,$(PATH))'';'    detected_OS := Windowselse    detected_OS := $(shell uname 2>/dev/null || echo Unknown)    detected_OS := $(patsubst CYGWIN%,Cygwin,$(detected_OS))    detected_OS := $(patsubst MSYS%,MSYS,$(detected_OS))    detected_OS := $(patsubst MINGW%,MSYS,$(detected_OS))endif

Then you can select the relevant stuff depending on detected_OS:

ifeq ($(detected_OS),Windows)    CFLAGS += -D WIN32endififeq ($(detected_OS),Darwin)        # Mac OS X    CFLAGS += -D OSXendififeq ($(detected_OS),Linux)    CFLAGS   +=   -D LINUXendififeq ($(detected_OS),GNU)           # Debian GNU Hurd    CFLAGS   +=   -D GNU_HURDendififeq ($(detected_OS),GNU/kFreeBSD)  # Debian kFreeBSD    CFLAGS   +=   -D GNU_kFreeBSDendififeq ($(detected_OS),FreeBSD)    CFLAGS   +=   -D FreeBSDendififeq ($(detected_OS),NetBSD)    CFLAGS   +=   -D NetBSDendififeq ($(detected_OS),DragonFly)    CFLAGS   +=   -D DragonFlyendififeq ($(detected_OS),Haiku)    CFLAGS   +=   -D Haikuendif

Notes:

  • Command uname is same as uname -s because option -s (--kernel-name) is the default. See why uname -s is better than uname -o.

  • The use of OS (instead of uname) simplifies the identification algorithm. You can still use solely uname, but you have to deal with if/else blocks to check all MinGW, Cygwin, etc. variations.

  • The environment variable OS is always set to "Windows_NT" on different Windows versions (see %OS% environment variable on Wikipedia).

  • An alternative of OS is the environment variable MSVC (it checks the presence of MS Visual Studio, see example using Visual C++).


Below I provide a complete example using make and gcc to build a shared library: *.so or *.dll depending on the platform. The example is as simplest as possible to be more understandable.

To install make and gcc on Windows see Cygwin or MinGW.

My example is based on five files

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

Reminder:Makefile is indented using tabulation. Caution when copy-pasting below sample files.

The two Makefile files

1. lib/Makefile

ifeq ($(OS),Windows_NT)    uname_S := Windowselse    uname_S := $(shell uname -s)endififeq ($(uname_S), Windows)    target = hello.dllendififeq ($(uname_S), Linux)    target = libhello.soendif#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111#    target = .....#endif%.o: %.c    gcc  -c $<  -fPIC  -o $@    # -c $<  => $< is first file after ':' => Compile hello.c    # -fPIC  => Position-Independent Code (required for shared lib)    # -o $@  => $@ is the target => Output file (-o) is hello.o$(target): hello.o    gcc  $^  -shared  -o $@    # $^      => $^ expand to all prerequisites (after ':') => hello.o    # -shared => Generate shared library    # -o $@   => Output file (-o) is $@ (libhello.so or hello.dll)

2. app/Makefile

ifeq ($(OS),Windows_NT)    uname_S := Windowselse    uname_S := $(shell uname -s)endififeq ($(uname_S), Windows)    target = app.exeendififeq ($(uname_S), Linux)    target = appendif#ifeq ($(uname_S), .....) #See https://stackoverflow.com/a/27776822/938111#    target = .....#endif%.o: %.c    gcc  -c $< -I ../lib  -o $@    # -c $<     => compile (-c) $< (first file after :) = main.c    # -I ../lib => search headers (*.h) in directory ../lib    # -o $@     => output file (-o) is $@ (target) = main.o$(target): main.o    gcc  $^  -L../lib  -lhello  -o $@    # $^       => $^ (all files after the :) = main.o (here only one file)    # -L../lib => look for libraries in directory ../lib    # -lhello  => use shared library hello (libhello.so or hello.dll)    # -o $@    => output file (-o) is $@ (target) = "app.exe" or "app"

To learn more, read Automatic Variables documentation as pointed out by cfi.

The source code

- lib/hello.h

#ifndef HELLO_H_#define HELLO_H_const char* hello();#endif

- lib/hello.c

#include "hello.h"const char* hello(){    return "hello";}

- app/main.c

#include "hello.h" //hello()#include <stdio.h> //puts()int main(){    const char* str = hello();    puts(str);}

The build

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

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

The make command is the same on both platforms. The given output is on Unix-like OSes:

> make -C libmake: Entering directory '/tmp/lib'gcc  -c hello.c  -fPIC  -o hello.o# -c hello.c  => hello.c is first file after ':' => Compile hello.c# -fPIC       => Position-Independent Code (required for shared lib)# -o hello.o  => hello.o is the target => Output file (-o) is hello.ogcc  hello.o  -shared  -o libhello.so# hello.o        => hello.o is the first after ':' => Link hello.o# -shared        => Generate shared library# -o libhello.so => Output file (-o) is libhello.so (libhello.so or hello.dll)make: Leaving directory '/tmp/lib'> make -C appmake: Entering directory '/tmp/app'gcc  -c main.c -I ../lib  -o main.o# -c main.c => compile (-c) main.c (first file after :) = main.cpp# -I ../lib => search headers (*.h) in directory ../lib# -o main.o => output file (-o) is main.o (target) = main.ogcc  main.o  -L../lib  -lhello  -o app# main.o   => main.o (all files after the :) = main.o (here only one file)# -L../lib => look for libraries in directory ../lib# -lhello  => use shared library hello (libhello.so or hello.dll)# -o app   => output file (-o) is app.exe (target) = "app.exe" or "app"make: Leaving directory '/tmp/app'

The run

The application requires to know where is the shared library.

On Windows, a simple solution is to copy the library where the application is:

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

On Unix-like OSes, you can use the LD_LIBRARY_PATH environment variable:

> export LD_LIBRARY_PATH=lib

Run the command on Windows:

> app/app.exehello

Run the command on Unix-like OSes:

> app/apphello

Viewing all articles
Browse latest Browse all 15

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>