Detect the operating system using two simple tricks:
- First the environment variable OS
- Then the unamecommand
ifeq ($(OS),Windows_NT)     # is Windows_NT on XP, 2000, 7, Vista, 10...    detected_OS := Windowselse    detected_OS := $(shell uname)  # same as "uname -s"endifOr 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')endifKen 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))endifThen 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 HaikuendifNotes:
- Command - unameis same as- uname -sbecause option- -s(- --kernel-name) is the default. See why- uname -sis 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/elseblocks to check all MinGW, Cygwin, etc. variations.
- The environment variable - OSis always set to- "Windows_NT"on different Windows versions (see- %OS%environment variable on Wikipedia).
- An alternative of - OSis 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.cReminder: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  */MakefileThe 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=libRun the command on Windows:
> app/app.exehelloRun the command on Unix-like OSes:
> app/apphello