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
The git makefile contains numerous examples of how to manage without autoconf/automake, yet still work on a multitude of unixy platforms.
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:
Then, in order to put this in your Makefile, start out with Makefile.in which should have something like
in it.
Use the following sed command in your configure script after the
UNAME=uname
bit.Now your makefile should have
UNAME
defined as desired. If/elif/else statements are all that's left!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 usegcc -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
:You can check the result in the makefile like this:
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, andgcc -dumpmachine
gives you the system for which you are compiling.Detect the operating system using two simple tricks:
OS
uname
commandOr a more safe way, if not on Windows and
uname
unavailable:Ken Jackson proposes an interesting alternative if you want to distinguish Cygwin/MinGW/MSYS/Windows. See his answer that looks like that:
Then you can select the relevant stuff depending on
detected_OS
:Notes:
Command
uname
is same asuname -s
because option-s
(--kernel-name
) is the default. See whyuname -s
is better thanuname -o
.The use of
OS
(instead ofuname
) simplifies the identification algorithm. You can still use solelyuname
, but you have to deal withif/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 variableMSVC
(it checks the presence of MS Visual Studio, see example using Visual C++).Below I provide a complete example using
make
andgcc
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
andgcc
on Windows see Cygwin or MinGW.My example is based on five files
Reminder:
Makefile
is indented using tabulation. Caution when copy-pasting below sample files.The two
Makefile
files1.
lib/Makefile
2.
app/Makefile
To learn more, read Automatic Variables documentation as pointed out by cfi.
The source code
-
lib/hello.h
-
lib/hello.c
-
app/main.c
The build
Fix the copy-paste of
Makefile
(replace leading spaces by one tabulation).The
make
command is the same on both platforms. The given output is on Unix-like OSes: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:
On Unix-like OSes, you can use the
LD_LIBRARY_PATH
environment variable:Run the command on Windows:
Run the command on Unix-like OSes:
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.
Here's a simple solution that checks if you are in a Windows or posix-like (Linux/Unix/Cygwin/Mac) environment:
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.