Vicky
Vicky

Reputation: 471

How to find a base architecture inside Makefile?

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

Answers (2)

gavv
gavv

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:

  • to detect host architecture, use config.guess shell script
  • to detect target architecture, use gcc -dumpmachine or gcc --help=target

Detecting host architecture

1) 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.

2) 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.

3) /proc

You can use /proc to gather architecture info, e.g. /proc/cpuinfo on Linux. However, it's not portable and hard to parse.

4) 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.


Detecting default target architecture of your toolchain

It usually makes sense to detect target architecture of toolchain being used. It's different from host architecture when cross-compiling.

1) 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:

  • It prints the value of --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.
  • Unlike config.guess, this toolchain tuple is distro-specific. E.g., different schemes are used in prebuilt toolchains in Debian and Gentoo.

2) 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.

3) 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:

  • on Debian, it's empty if multilib is disabled
  • on Gentoo, it's always empty
  • as mentioned by @Dummy00001, it may be empty for cross-compilation toolchains (I guess it depends on how toolchain was built)

Detecting target architecture depending on current flags

Some GCC options like -m32 or -march can affect target architecture.

1) 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

Dummy00001
Dummy00001

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

Related Questions