For example, I am trying to test whether this works in my makefile preamble:
ifneq (,$(shell latexmk --version 2>/dev/null))
echo Works
else
echo Does not Works
endif
all:
do things...
Which does the error:
*** recipe commences before first target. Stop.
Then, how to prints things outside rules?
Makefile does not allow commands outside rules, or outside result:=$(shell ...).
In GNU Make there are $(info ...), $(warning ...) and $(error ...) built-in functions. Note that syntactically they are text substitutions, yet their return value is always an empty string (except $(error ...) which never returns), as it's with $(eval ...) etc. So they could be used almost everywhere.
Yet another option is $(file >/dev/stdout,...) (under Windows use "con").
After I found this question, https://unix.stackexchange.com/questions/464754/how-to-see-from-which-file-descriptor-output-is-coming
I think this kinda works:
ifneq (,$(shell latexmk --version 2>/dev/null))
useless := $(shell echo Works 1>&2)
else
useless := $(shell echo Does not Works 1>&2)
useless := $(error exiting...)
endif
all:
echo Hey sister, do you still believe in love I wonder...
Bonus:
Can I make a makefile abort outside of a rule?
I have the following in my GNU makefile:
# Undefined Behavior Sanitizer (Clang 3.2 and GCC 4.8 and above)
UBSAN = 0
ifeq ($(findstring ubsan,$(MAKECMDGOALS)),ubsan)
UBSAN = 1
CXXFLAGS += -fsanitize=undefined
endif # UBsan
# Address Sanitizer (Clang 3.2 and GCC 4.8 and above)
ASAN = 0
ifeq ($(findstring asan,$(MAKECMDGOALS)),asan)
ASAN = 1
CXXFLAGS += -fsanitize=address
endif # Asan
# Effectively a NOR
ifneq ($(shell echo $$($(ASAN) * $(UBSAN))),0)
$(error Asan and UBsan are mutually exclusive. Specify only one of them)
endif
The idea is to detect make ubsan asan (or user overrides to CFLAGS and CXXFLAGS), and error out if both are specified.
Unfortunately, its firing with no command targets:
$ make
/bin/sh: 1: 0: not found
GNUmakefile:64: *** Asan and UBsan are mutually exclusive. Specify only one of them. Stop.
I also tried quoting the "0" with the same result: ifneq ($(shell echo $$($(ASAN) * $(UBSAN))),"0").
How do I compare two integral values in a makefile?
Your problem is a simple typo.
You left out one (/) in the arithmetic expansion in the $(shell) command.
Your shell command is echo $(0 * 0) which the shell sees as a command substitution not arithmetic expansion and then tries to run 0 <expansion of all files in the current directory> 0. Which is why you get the /bin/sh: 1: 0: not found error message.
Add the missing (/) and your problem goes away.
ifneq ($(shell echo $$(($(ASAN) * $(UBSAN)))),0)
That being said I wouldn't bother using the shell for this at all (it is expensive).
All you are trying to test, in this case, is that $(ASAN) and $(UBSAN) are not both 1. So just assert that.
ifeq ($(ASAN)$(UBSAN),11)
$(error Asan and UBsan are mutually exclusive. Specify only one of them)
endif
If you want to be safer about manual assignment of some other value (e.g. make ASAN=11 or something) then you could do something more like:
ifeq ($(filter-out 1,$(ASAN))$(filter-out 1,$(UBSAN)),)
$(error Asan and UBsan are mutually exclusive. Specify only one of them)
endif
I'm trying to get SFML to work with Eclipse but I'm unsuccessfull(running MinGW 3.17-2 and gcc 4.8.1)
The file is compiled but when I try to run it I get the following error:
Looking in my MinGW\bin folder I can only see a libgcc_s_dw2-1.dll file and after some searching it appears that the dll asked for is for a 64-bit version? My OS is 64 bit but both MinGW and the SFML libraries all 32-bit.
How can I resolve this?
Makefile:
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
-include ../makefile.init
RM := rm -rf
# All of the sources participating in the build are defined here
-include sources.mk
-include subdir.mk
-include objects.mk
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(CC_DEPS)),)
-include $(CC_DEPS)
endif
ifneq ($(strip $(C++_DEPS)),)
-include $(C++_DEPS)
endif
ifneq ($(strip $(C_UPPER_DEPS)),)
-include $(C_UPPER_DEPS)
endif
ifneq ($(strip $(CXX_DEPS)),)
-include $(CXX_DEPS)
endif
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
ifneq ($(strip $(CPP_DEPS)),)
-include $(CPP_DEPS)
endif
endif
-include ../makefile.defs
# Add inputs and outputs from these tool invocations to the build variables
# All Target
all: Test
# Tool invocations
Test: $(OBJS) $(USER_OBJS)
#echo 'Building target: $#'
#echo 'Invoking: Cross G++ Linker'
g++ -L"F:\Libs\SFML-2.2\lib" -o "Test" $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
# Other Targets
clean:
-$(RM) $(CC_DEPS)$(C++_DEPS)$(EXECUTABLES)$(OBJS)$(C_UPPER_DEPS)$(CXX_DEPS)$(C_DEPS)$(CPP_DEPS) Test
-#echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets
objects.mk:
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
USER_OBJS :=
LIBS := -lsfml-graphics-d -lsfml-system-d -lsfml-window-d
sources.mk:
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
C_UPPER_SRCS :=
CXX_SRCS :=
C++_SRCS :=
OBJ_SRCS :=
CC_SRCS :=
ASM_SRCS :=
C_SRCS :=
CPP_SRCS :=
O_SRCS :=
S_UPPER_SRCS :=
CC_DEPS :=
C++_DEPS :=
EXECUTABLES :=
OBJS :=
C_UPPER_DEPS :=
CXX_DEPS :=
C_DEPS :=
CPP_DEPS :=
# Every subdirectory with source files must be described here
SUBDIRS := \
. \
subdir.mk
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../main.cpp
OBJS += \
./main.o
CPP_DEPS += \
./main.d
# Each subdirectory must supply rules for building sources it contributes
%.o: ../%.cpp
#echo 'Building file: $<'
#echo 'Invoking: Cross G++ Compiler'
g++ -I"F:\Libs\SFML-2.2\include" -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"$(#:%.o=%.d)" -MT"$(#:%.o=%.d)" -o "$#" "$<"
#echo 'Finished building: $<'
#echo ' '
Due to the way name mangling and non-standardized ABI work in C++, there is unfortunately about no compatibility between different versions of compilers. In your case, you're even trying to use a library compiled with a compiler from a different "MinGW" project than your current compiler is. But even if you were using the same "type" of compiler, C++ libraries usually aren't reusable across minor or patch versions.
First of I really recommend to not use the original MinGW project and rather go for a compiler based on the MinGW-w64 project. If you want reasons for that, you can ask Google, there are enough discussion about it.
Second you either need to pick a compiler that matches on of the SFML packages OR you need to build SFML yourself.
For the GCC 4.9.2 MinGW (DW2) - 32-bit package I used this compiler.
For the GCC 4.7.1 TDM (SJLJ) - 32-bit package I used the compiler that shipped with this Code::Blocks package.
For the GCC 4.8.1 TDM (SJLJ) - 32-bit package I used the compiler that shipped with this Code::Blocks package.
And third, if you want the latest development version of SFML using the latest compiler versions, you can check out my Nightly Builds.
What is the appropriate form for a clean target for a portable Makefile? $(RM) does not work for me. I work both from the Windows (7) command prompt and within Eclipse. They both report the same version of make (I do have multiple on my path):
make --version
GNU Make 3.82
Built for i386-pc-mingw32
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Within Eclipse:
make clean
rm -f *.o testScaffolding_* runner.cpp runner.exe *.d
From cmd:
rm -f *.o testScaffolding_* runner.cpp runner.exe *.d
process_begin: CreateProcess(NULL, rm -f *.o testScaffolding_* runner.cpp runner.exe *.d, ...) failed.
make (e=2): The system cannot find the file specified.
make: *** [clean] Error 2
Both report $(OS) as Windows_NT and $(RM) as rm -f. I have which installed as well and if I call it within the Makefile, both environments report the same path.
This is the best I've come up with so far. You can specify UNAME as an environment variable or on the command line. If not specified it tries to run uname. If that fails it assumes Windows. Subsequently, you have a reasonable guess as to your shell environment and can define the corresponding commands appropriately.
Note that this has seen only limited testing and I merely consider it functional, not elegant or 'correct'. Also, the likes of an executable extension (.exe vs. nothing) is probably better identified by the use of $(OS).
ifeq ($(strip $(UNAME)),)
# if not already specified, try running uname
UNAME = $(shell uname)
endif
ifeq ($(strip $(UNAME)),)
# if still not specified, assume Windows
UNAME = Windows
endif
ifeq ($(UNAME),Windows)
define TO_WIN
$(subst /,\,$1)
endef
define MKDIR
-mkdir $(call TO_WIN,$1)
endef
define RM
del $(call TO_WIN,$1)
endef
CAT := type
else
define MKDIR
mkdir -p $1
endef
define RM
rm -f $1
endef
CAT := cat
endif
I routinely work on several different computers and several different operating systems, which are Mac OS X, Linux, or Solaris. For the project I'm working on, I pull my code from a remote git repository.
I like to be able to work on my projects regardless of which terminal I'm at. So far, I've found ways to get around the OS changes by changing the makefile every time I switch computers. However, this is tedious and causes a bunch of headaches.
How can I modify my makefile so that it detects which OS I'm using and modifies syntax accordingly?
Here is the makefile:
cc = gcc -g
CC = g++ -g
yacc=$(YACC)
lex=$(FLEX)
all: assembler
assembler: y.tab.o lex.yy.o
$(CC) -o assembler y.tab.o lex.yy.o -ll -l y
assembler.o: assembler.c
$(cc) -o assembler.o assembler.c
y.tab.o: assem.y
$(yacc) -d assem.y
$(CC) -c y.tab.c
lex.yy.o: assem.l
$(lex) assem.l
$(cc) -c lex.yy.c
clean:
rm -f lex.yy.c y.tab.c y.tab.h assembler *.o *.tmp *.debug *.acts
There are many good answers here already, but I wanted to share a more complete example that both:
doesn't assume uname exists on Windows
also detects the processor
The CCFLAGS defined here aren't necessarily recommended or ideal; they're just what the project to which I was adding OS/CPU auto-detection happened to be using.
ifeq ($(OS),Windows_NT)
CCFLAGS += -D WIN32
ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
CCFLAGS += -D AMD64
else
ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
CCFLAGS += -D AMD64
endif
ifeq ($(PROCESSOR_ARCHITECTURE),x86)
CCFLAGS += -D IA32
endif
endif
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
CCFLAGS += -D LINUX
endif
ifeq ($(UNAME_S),Darwin)
CCFLAGS += -D OSX
endif
UNAME_P := $(shell uname -p)
ifeq ($(UNAME_P),x86_64)
CCFLAGS += -D AMD64
endif
ifneq ($(filter %86,$(UNAME_P)),)
CCFLAGS += -D IA32
endif
ifneq ($(filter arm%,$(UNAME_P)),)
CCFLAGS += -D ARM
endif
endif
The uname command (http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/uname.1.html) with no parameters should tell you the operating system name. I'd use that, then make conditionals based on the return value.
Example
UNAME := $(shell uname)
ifeq ($(UNAME), Linux)
# do something Linux-y
endif
ifeq ($(UNAME), Solaris)
# do something Solaris-y
endif
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 := Windows
else
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 := Windows
else
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 := Windows
else
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 WIN32
endif
ifeq ($(detected_OS),Darwin) # Mac OS X
CFLAGS += -D OSX
endif
ifeq ($(detected_OS),Linux)
CFLAGS += -D LINUX
endif
ifeq ($(detected_OS),GNU) # Debian GNU Hurd
CFLAGS += -D GNU_HURD
endif
ifeq ($(detected_OS),GNU/kFreeBSD) # Debian kFreeBSD
CFLAGS += -D GNU_kFreeBSD
endif
ifeq ($(detected_OS),FreeBSD)
CFLAGS += -D FreeBSD
endif
ifeq ($(detected_OS),NetBSD)
CFLAGS += -D NetBSD
endif
ifeq ($(detected_OS),DragonFly)
CFLAGS += -D DragonFly
endif
ifeq ($(detected_OS),Haiku)
CFLAGS += -D Haiku
endif
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 := Windows
else
uname_S := $(shell uname -s)
endif
ifeq ($(uname_S), Windows)
target = hello.dll
endif
ifeq ($(uname_S), Linux)
target = libhello.so
endif
#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 := Windows
else
uname_S := $(shell uname -s)
endif
ifeq ($(uname_S), Windows)
target = app.exe
endif
ifeq ($(uname_S), Linux)
target = app
endif
#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 lib
make: 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.o
gcc 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 app
make: 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.o
gcc 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.exe
hello
Run the command on Unix-like OSes:
> app/app
hello
I was recently experimenting in order to answer this question I was asking myself. Here are my conclusions:
Since in Windows, you can't be sure that the uname command is available, you can use gcc -dumpmachine. This will display the compiler target.
There may be also a problem when using uname if you want to do some cross-compilation.
Here's a example list of possible output of gcc -dumpmachine:
mingw32
i686-pc-cygwin
x86_64-redhat-linux
You can check the result in the makefile like this:
SYS := $(shell gcc -dumpmachine)
ifneq (, $(findstring linux, $(SYS)))
# Do Linux things
else ifneq(, $(findstring mingw, $(SYS)))
# Do MinGW things
else ifneq(, $(findstring cygwin, $(SYS)))
# Do Cygwin things
else
# Do things for others
endif
It worked well for me, but I'm not sure it's a reliable way of getting the system type. At least it's reliable about MinGW and that's all I need since it does not require to have the uname command or MSYS package in Windows.
To sum up, uname gives you the system on which you're compiling, and gcc -dumpmachine gives you the system for which you are compiling.
The git makefile contains numerous examples of how to manage without autoconf/automake, yet still work on a multitude of unixy platforms.
Update: I now consider this answer to be obsolete. I posted a new perfect solution further down.
If your makefile may be running on non-Cygwin Windows, uname may not be available. That's awkward, but this is a potential solution. You have to check for Cygwin first to rule it out, because it has WINDOWS in its PATH environment variable too.
ifneq (,$(findstring /cygdrive/,$(PATH)))
UNAME := Cygwin
else
ifneq (,$(findstring WINDOWS,$(PATH)))
UNAME := Windows
else
UNAME := $(shell uname -s)
endif
endif
That's the job that GNU's automake/autoconf are designed to solve. You might want to investigate them.
Alternatively you can set environment variables on your different platforms and make you Makefile conditional against them.
I ran into this problem today and I needed it on Solaris so here is a POSIX standard way to do (something very close to) this.
#Detect OS
UNAME = `uname`
# Build based on OS name
DetectOS:
-#make $(UNAME)
# OS is Linux, use GCC
Linux: program.c
#SHELL_VARIABLE="-D_LINUX_STUFF_HERE_"
rm -f program
gcc $(SHELL_VARIABLE) -o program program.c
# OS is Solaris, use c99
SunOS: program.c
#SHELL_VARIABLE="-D_SOLARIS_STUFF_HERE_"
rm -f program
c99 $(SHELL_VARIABLE) -o program program.c
I finally found the perfect solution that solves this problem for me.
ifeq '$(findstring ;,$(PATH))' ';'
UNAME := Windows
else
UNAME := $(shell uname 2>/dev/null || echo Unknown)
UNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))
UNAME := $(patsubst MSYS%,MSYS,$(UNAME))
UNAME := $(patsubst MINGW%,MSYS,$(UNAME))
endif
The UNAME variable is set to Linux, Cygwin, MSYS, Windows, FreeBSD, NetBSD (or presumably Solaris, Darwin, OpenBSD, AIX, HP-UX), or Unknown. It can then be compared throughout the remainder of the Makefile to separate any OS-sensitive variables and commands.
The key is that Windows uses semicolons to separate paths in the PATH variable whereas everyone else uses colons. (It's possible to make a Linux directory with a ';' in the name and add it to PATH, which would break this, but who would do such a thing?) This seems to be the least risky method to detect native Windows because it doesn't need a shell call. The Cygwin and MSYS PATH use colons so uname is called for them.
Note that the OS environment variable can be used to detect Windows, but not to distinguish between Cygwin and native Windows. Testing for the echoing of quotes works, but it requires a shell call.
Unfortunately, Cygwin adds some version information to the output of uname, so I added the 'patsubst' calls to change it to just 'Cygwin'. Also, uname for MSYS actually has three possible outputs starting with MSYS or MINGW, but I use also patsubst to transform all to just 'MSYS'.
If it's important to distinguish between native Windows systems with and without some uname.exe on the path, this line can be used instead of the simple assignment:
UNAME := $(shell uname 2>NUL || echo Windows)
Of course in all cases GNU make is required, or another make which supports the functions used.
Here's a simple solution that checks if you are in a Windows or posix-like (Linux/Unix/Cygwin/Mac) environment:
ifeq ($(shell echo "check_quotes"),"check_quotes")
WINDOWS := yes
else
WINDOWS := no
endif
It takes advantage of the fact that echo exists on both posix-like and Windows environments, and that in Windows the shell does not filter the quotes.
Note that Makefiles are extremely sensitive to spacing. Here's an example of a Makefile that runs an extra command on OS X and which works on OS X and Linux. Overall, though, autoconf/automake is the way to go for anything at all non-trivial.
UNAME := $(shell uname -s)
CPP = g++
CPPFLAGS = -pthread -ansi -Wall -Werror -pedantic -O0 -g3 -I /nexopia/include
LDFLAGS = -pthread -L/nexopia/lib -lboost_system
HEADERS = data_structures.h http_client.h load.h lock.h search.h server.h thread.h utility.h
OBJECTS = http_client.o load.o lock.o search.o server.o thread.o utility.o vor.o
all: vor
clean:
rm -f $(OBJECTS) vor
vor: $(OBJECTS)
$(CPP) $(LDFLAGS) -o vor $(OBJECTS)
ifeq ($(UNAME),Darwin)
# Set the Boost library location
install_name_tool -change libboost_system.dylib /nexopia/lib/libboost_system.dylib vor
endif
%.o: %.cpp $(HEADERS) Makefile
$(CPP) $(CPPFLAGS) -c $
Another way to do this is by using a "configure" script. If you are already using one with your makefile, you can use a combination of uname and sed to get things to work out. First, in your script, do:
UNAME=uname
Then, in order to put this in your Makefile, start out with Makefile.in which should have something like
UNAME=##UNAME##
in it.
Use the following sed command in your configure script after the UNAME=uname bit.
sed -e "s|##UNAME##|$UNAME|" < Makefile.in > Makefile
Now your makefile should have UNAME defined as desired. If/elif/else statements are all that's left!
I had a case where I had to detect the difference between two versions of Fedora, to tweak the command-line options for inkscape:
- in Fedora 31, the default inkscape is 1.0beta which uses --export-file
- in Fedora < 31, the default inkscape is 0.92 which uses --export-pdf
My Makefile contains the following
# set VERSION_ID from /etc/os-release
$(eval $(shell grep VERSION_ID /etc/os-release))
# select the inkscape export syntax
ifeq ($(VERSION_ID),31)
EXPORT = export-file
else
EXPORT = export-pdf
endif
# rule to convert inkscape SVG (drawing) to PDF
%.pdf : %.svg
inkscape --export-area-drawing $< --$(EXPORT)=$#
This works because /etc/os-release contains a line
VERSION_ID=<value>
so the shell command in the Makefile returns the string VERSION_ID=<value>, then the eval command acts on this to set the Makefile variable VERSION_ID.
This can obviously be tweaked for other OS's depending how the metadata is stored. Note that in Fedora there is not a default environment variable that gives the OS version, otherwise I would have used that!
An alternate way that I have not seen anyone talking about is using the built-in variable SHELL. The program used as the shell is taken from the variable SHELL. On MS-Windows systems, it is most likely to be an executable file with .exe extension (like sh.exe).
In that case, the following conditional test:
ifeq ($(suffix $(SHELL)),.exe)
# Windows system
else
# Non-Windows system
endif
Would have the same result as using the environment variable OS:
ifeq ($(OS),Windows_NT)
# Windows system
else
# Non-Windows system
endif
However, it seems the latter is the most popular solution, so I would recommend you stick with it.