Nokia Networks Home

Nokia nmake Product Builder

Quick Links

Related Products

How to build both 32-bit and 64-bit versions of targets?

There are a few techniques available to build both 32-bit and 64-bit targets. The best approach depends on the specific needs of the project. A major problem with building two versions of targets from one set of files is to make sure the intermediate files, such as .o files, do not clobber each other so incremental updates are properly supported. The following techniques also allow different values of CC to be used and thus different probe files, which may be important. See Probe Considerations below for details.

The examples assume the compiler uses the -m32 and -m64 flags to target 32-bit and 64-bit output respectively but compiler tool chains may vary.

Separate Viewpath Nodes

When delivering separate 32-bit and 64-bit versions of the entire product it makes sense to build them separately in different viewpath nodes using a common node for the source code. The builds are treated as separate platform builds and do not impact each other. This approach does not require logic changes to makefiles and should be relatively easy to set up.

The current build directory can be used to determine the build type and enable the appropriate compiler options. Alternatively a variable can be used to specify the build type since developers' build directories may be named differently. The following example can be used in the global makefile to enable the appropriate compiler option based on the directory or the BITS variable. Note that the directory name takes precedence over the BITS variable so using the wrong BITS value in a known build directory won't pollute the build. Otherwise setting BITS=64 on the nmake command line enables the 64-bit build.

CC = cc

if "$(PWD:N=*/platform/*64*)"
	CCFLAGS += -m64
elif "$(PWD:N=*/platform/*32*)"
	CCFLAGS += -m32
elif "$(BITS:N=64)"
	CCFLAGS += -m64
else
	CCFLAGS += -m32
end

Run the 32-bit build in its build directory.

$ echo $VPATH
/builds/proj1.0/platform/sol32:/builds/proj1.0/source

$ cd /builds/proj1.0/platform/sol32/src

$ nmake install
+ cc -O -m32 -I- -c /builds/proj1.0/source/src/a.c
+ cc -O -m32 -I- -c /builds/proj1.0/source/src/b.c
+ cc -O -m32 -I- -c /builds/proj1.0/source/src/c.c
+ cc -O -m32 -o targ a.o b.o c.o
+ cp targ ../bin/targ

Run the 64-bit build in its build directory.

$ echo $VPATH
/builds/proj1.0/platform/sol64:/builds/proj1.0/source

$ cd /builds/proj1.0/platform/sol64/src

$ nmake install
+ cc -O -m64 -I- -c /builds/proj1.0/source/src/a.c
+ cc -O -m64 -I- -c /builds/proj1.0/source/src/b.c
+ cc -O -m64 -I- -c /builds/proj1.0/source/src/c.c
+ cc -O -m64 -o targ a.o b.o c.o
+ cp targ ../bin/targ

When building in some other directory specify BITS=64 to build the 64-bit targets, otherwise the 32-bit targets are built by default.

$ echo $VPATH
/home/richb/proj1.0:/builds/proj1.0/source

$ cd /home/richb/proj1.0/src

$ nmake BITS=64 install        
+ cc -O -m64 -I- -c /builds/proj1.0/source/src/a.c
+ cc -O -m64 -I- -c /builds/proj1.0/source/src/b.c
+ cc -O -m64 -I- -c /builds/proj1.0/source/src/c.c
+ cc -O -m64 -o targ a.o b.o c.o
+ cp targ ../bin/targ

Recurse to Separate Directories

When some components needs to be delivered with the product as both 32-bit and 64-bit then it may make sense to build both versions together. One approach uses separate directories for the 32-bit and 64-bit compiles. In the following example the source code is in a parent directory. The Makefile in the parent recurses to the sub-directories for each target version. The Makefiles in the sub-directories just include a common makefile from the parent for building the code which keys off the directory name to build the 32-bit or 64-bit versions.

$ ls -l
total 16
drwxr-xr-x 2 richb richb 4096 Oct 18 17:14 32bit
drwxr-xr-x 2 richb richb 4096 Oct 18 17:14 64bit
-rw-r--r-- 1 richb richb   19 Oct 18 16:43 Makefile
-rw-r--r-- 1 richb richb   59 Oct 18 16:41 a.c
-rw-r--r-- 1 richb richb   58 Oct 18 16:41 b.c
-rw-r--r-- 1 richb richb   74 Oct 18 16:41 c.c
-rw-r--r-- 1 richb richb   99 Oct 18 17:12 cmd.mk

$ cat Makefile 
:MAKE: 32bit 64bit

$ cat cmd.mk
CC = cc
BIT := $(PWD:B:C/bit//)
CCFLAGS += -m$(BIT)

.SOURCE: ..

:ALL:

targ$(BIT) :: a.c b.c c.c

$ cat 32bit/Makefile 
include ../cmd.mk

$ cat 64bit/Makefile 
include ../cmd.mk

$ nmake
32bit:
+ cc -O -m32 -I- -c ../a.c
+ cc -O -m32 -I- -c ../b.c
+ cc -O -m32 -I- -c ../c.c
+ cc -O -m32 -o targ32 a.o b.o c.o
64bit:
+ cc -O -m64 -I- -c ../a.c
+ cc -O -m64 -I- -c ../b.c
+ cc -O -m64 -I- -c ../c.c
+ cc -O -m64 -o targ64 a.o b.o c.o

$ vi b.c

$ nmake
32bit:
+ cc -O -m32 -I- -c ../b.c
+ cc -O -m32 -o targ32 a.o b.o c.o
64bit:
+ cc -O -m64 -I- -c ../b.c
+ cc -O -m64 -o targ64 a.o b.o c.o

Recurse to Same Directory

Another approach is to recurse the same directory multiple times using different makefiles to build each target version. To make maintenance easier all the rules to build both versions are in the first makefile. It uses the current makefile name to determine which version to build. The second makefile just includes the first one. A custom metarule is used to prevent object files from clobbering each other.

$ ls -l
total 8
-rw-r--r-- 1 richb richb  27 Oct 20 15:05 Makefile
-rw-r--r-- 1 richb richb  59 Oct 20 14:58 a.c
-rw-r--r-- 1 richb richb  58 Oct 20 14:58 b.c
-rw-r--r-- 1 richb richb  74 Oct 20 14:58 c.c
-rw-r--r-- 1 richb richb 244 Oct 20 15:11 cmd32.mk
-rw-r--r-- 1 richb richb  34 Oct 20 15:10 cmd64.mk

$ cat Makefile
:MAKE: cmd32.mk cmd64.mk

$ cat cmd32.mk
CC = cc
FILES = a.c b.c c.c
OBJ32 = $(FILES:B:S=.o)
OBJ64 = $(FILES:B:S=64.o)

%64.o : %.c (CC) (CCFLAGS)
        $(CC) $(CCFLAGS) -o $(<) -c $(>)

:ALL:

if "$(MAKEFILE:N=*64.mk)"
        CCFLAGS += -m64
        targ64 :: $(OBJ64)
else
        CCFLAGS += -m32
        targ32 :: $(OBJ32)
end

$ cat cmd64.mk 
include cmd32.mk

$ nmake
cmd32.mk:
+ cc -O -m32 -I- -c a.c
+ cc -O -m32 -I- -c b.c
+ cc -O -m32 -I- -c c.c
+ cc -O -m32 -o targ32 a.o b.o c.o
cmd64.mk:
+ cc -O -m64 -I- -o a64.o -c a.c
+ cc -O -m64 -I- -o b64.o -c b.c
+ cc -O -m64 -I- -o c64.o -c c.c
+ cc -O -m64 -o targ64 a64.o b64.o c64.o

$ vi b.c

$ nmake
cmd32.mk:
+ cc -O -m32 -I- -c b.c
+ cc -O -m32 -o targ32 a.o b.o c.o
cmd64.mk:
+ cc -O -m64 -I- -o b64.o -c b.c
+ cc -O -m64 -o targ64 a64.o b64.o c64.o

Probe Considerations

The nmake probe tool configures nmake for the compiler tool chain and platform environment. See the probe FAQ for details. In cases where the compiler searches different include and/or library directories based on the 32/64-bit options, the compiler should be probed with the option so nmake is aware of the proper search directories and settings. When not using the proper probe configuration nmake will reference headers and libraries for the compiler's default bit model rather than that specified by the compiler flag which could be prone to build problems.

For such compilers it is preferred to include the compiler flag in the CC variable instead of CCFLAGS so nmake will probe the compiler for the specific configuration (eg. CC = cc -m64). Such compiler tool chains include versions of GCC, Solaris Studio and possibly others. The methods described above can be easily adapted to use CC and thus use different probe configurations for the different types of compiles.

As of nmake 13 probing the compiler with an alternate bit model does not work properly and results in wrong settings related to shared libraries. For example, if the compiler defaults to 32-bit then using CC = cc -m64 sets some probe variables wrong. This was fixed in nmake 14, see the Release Notes.

Other Options

For more general techniques to build the same source files with different compiler options see the FAQ, How to compile the same code with different compiler options?

Last Update: Friday,12-Aug-2016 10:43:40 EDT