Reputation: 471
I want to find inside a Makefile, whether I'm running on a 32-bit or 64-bit machine.
Is there any macro or environment variables that can be simply accessed from within Makefile?
I found this related answer on-line:
LBITS := $(shell getconf LONG_BIT)
ifeq ($(LBITS),64)
# do 64 bit stuff here, like set some CFLAGS
else
# do 32 bit stuff here
endif
However, I doubt in all system getconf
tool would be available or not.
Upvotes: 6
Views: 9094
Reputation: 4893
tl;dr;
If all you need is to get the number of bits in long
type in C in a portable way, it's ok to use getconf LONG_BIT
.
Otherwise:
config.guess
shell scriptgcc -dumpmachine
or gcc --help=target
getconf
As mentioned by @Dummy00001, getconf
is part of POSIX and is widely available, but it doesn't provide enough information.
Note that getconf LONG_BIT
is just the number of bits in long
type in C. E.g., it may be 32 on 16-bit or 64-bit machines. It's quite useless for determining host architecture.
uname
uname
is part of POSIX as well, and it doesn't provide enough information too.
For example, it doesn't distinguish between hardfloat and softfloat ARM on Linux. Also, its architecture naming is not really portable.
/proc
You can use /proc
to gather architecture info, e.g. /proc/cpuinfo
on Linux. However, it's not portable and hard to parse.
config.guess
Finally, I recommend GNU config.guess
script (source code). It is a standalone script that you can copy to your project. It is written in portable shell and should work on any UNIX.
$ sh config.guess
x86_64-pc-linux-gnu
This script is used in autotools, but you can use it without autotools too.
It usually makes sense to detect target architecture of toolchain being used. It's different from host architecture when cross-compiling.
gcc -E
You can parse gcc -E
output to get toolchain tuple for target architecture of gcc:
$ gcc -v -E - </dev/null |& grep Target:
Target: x86_64-linux-gnu
This should work on any UNIX if you use GCC or clang.
Notes:
--target
option passed to configure
script when GCC was built. It's not affected by current compilations flags passed to GCC, like -m32
or -march
.config.guess
, this toolchain tuple is distro-specific. E.g., different schemes are used in prebuilt toolchains in Debian and Gentoo.gcc -dumpmachine
It seems that gcc -dumpmachine
prints the same value as previous recipe:
$ gcc -dumpmachine
x86_64-linux-gnu
It works with GCC and clang.
gcc -print-multiarch
Another way to get toolchain tuple:
$ gcc -print-multiarch
x86_64-linux-gnu
It works with GCC, but not clang. Also, this option is known not to work in various cases:
Some GCC options like -m32
or -march
can affect target architecture.
gcc --help=target
This will print value of -march
option deduced from default target architecture (configured when GCC was built) and current compilation options.
$ gcc -Q --help=target |& grep -e -march | awk '{print $2}'
x86-64
$ gcc -m32 -Q --help=target |& grep -e -march | awk '{print $2}'
i686
$ gcc -march=i386 -Q --help=target |& grep -e -march | awk '{print $2}'
i386
It doesn't work with clang.
Upvotes: 12
Reputation: 17420
The getconf
is a POSIX tool, it should be available on all unix-like systems. But uname -m
would be more portable and more traditional way to find the type of the system.
Otherwise, with high probability, you are looking in the wrong direction: the bit-ness of the host system doesn't necessarily match the bit-ness of the tool-chain. Tool-chain (compiler, linker) define what bit-ness the result would be. And the tool-chain could be customized by the user to accommodate for the local needs (e.g. compiling as 32-bit on a 64-bit OS), or even cross-compilation.
To find the bit-ness of the GCC (or clang) in your tool-chain, you can use that:
LBITS := $(shell $(CC) $(CFLAGS) -dM -E - </dev/null | grep -q "__LP64__" && echo 64 || echo 32)
Effectively, it queries what bit-ness the application is going to be compiled with, without doing actual compilation, but peeking at the compiler defines for the LP parameter, which denotes the "data model" of the architecture (LP64 means "long and pointer are 64-bit" (and, by omission, int is 32 bit); ILP32 means "int, long and pointer are 32-bit").
As long as you stay on the Linux, that would work. (You need to use the CFLAGS
in the compiler invocation, since CFLAGS
overridden by the user could use the -m32
or -m64
options to change the bit-ness of the output code.)
Upvotes: 2