How do I use a conditional in nmake [duplicate] - nmake

I've got a Makefile.mak where I optionally create a test.exe or a DLL from my C-based source code. I'm using CL.EXE and NMAKE.
I'd like to modify my CFLAGS macro like this when the target is TEST.EXE:
CFLAGS = $(CFLAGS) -DMAIN
And, of course, I use this in my C code:
#ifdef MAIN
... int main()... yada yada
#endif
I had tried
!IF $# == "test.exe"
but it crashed out and doesn't work logically since the $#, target, isn't deterministic in that part of the makefile.
The logical place to define the additional macro is when defining the target but I don't see how to do that without NMAKE interpreting it as DOS command.
test.exe: test.obj
CFLAGS = $(CFLAGS) -DMAIN
$(LINKER) /out:$# $(LIB) $*.obj $(LIBS)
It'd be easier with gmake, I know. I don't have that option.

I will present two solutions: one which does what you request, namely modifying CFLAGS based on the target, and a second one which may be a better approach.
Suppose you have a file multiply.c:
#include <stdio.h>
int multiply(int a, int b) {
return a * b;
}
#ifdef MAIN
int main() {
printf("Unit test: multiply(2, 3) = %d\n", multiply(2, 3));
}
#endif
which you would like to add to a static library my_lib.lib, and also use as a stand-alone unit test.
One standard way of adding -DMAIN to CFLAGS is to use NMAKE recursively. The second invocation of NMAKE could use a different makefile or, as as presented here, use the same makefile with a flag to prevent an infinite recursive loop.
TARGETS = my_lib.lib multiply.exe
CFLAGS = -W4 -O2 -nologo -Zi
all: $(TARGETS)
my_lib.lib: multiply.obj
my_lib.lib:
lib -nologo -out:$# $**
!ifndef RECURSE
multiply.exe:
nmake -nologo CFLAGS="-DMAIN $(CFLAGS)" RECURSE= $#
!endif
multiply.obj: .FORCE
.FORCE:
If RECURSE is defined, the built-in rule is used to create the test program multiply.exe.
This solution works. But it requires that multiply.obj be remade every time it is used, because there are two versions of it floating around: one with a main and one without.
The second solution distinguishes between these object files.
TARGETS = my_lib.lib multiply.exe
CFLAGS = -W4 -O2 -nologo -Zi
all: $(TARGETS)
my_lib.lib: multiply.obj
multiply.exe: $*.TEST_obj
my_lib.lib:
lib -nologo -out:$# $**
multiply.exe:
link -nologo -out:$# $**
.c.TEST_obj:
$(CC) -DMAIN $(CFLAGS) -c $< -Fo$#
This gives:
>nmake -nologo
cl -W4 -O2 -nologo -Zi /c multiply.c
multiply.c
lib -nologo -out:my_lib.lib multiply.obj
cl -DMAIN -W4 -O2 -nologo -Zi -c multiply.c -Fomultiply.TEST_obj
multiply.c
link -nologo -out:multiply.exe multiply.TEST_obj
Trying to create a .exe file directly from the .c file, as in:
.c.exe:
$(CC) -DMAIN $(CFLAGS) $<
does not work, because this still creates a .obj file which clobbers the other version.
Edit: .SUFFIXES: .TEST_obj does not seem to be needed.

Related

Linking issue in Cross Compilation for arm in linux using aarch64-linux-gnu-

I got an error when try to link (-aarch64-linux-gnu-ld) (the script containing the Makefile was downloaded from https://github.com/Icenowy/aw-el2-barebone). Error is "aarch64-linux-gnu-ld: Error: unable to disambiguate: -nostartfiles (did you mean --nostartfiles ?)
make: *** [Makefile:31: el2-bb.elf] Error 1" How to recode the line 31? of the Makefile
CROSS_COMPILE = /usr/bin/aarch64-linux-gnu-
DEBUG = 1
CC = $(CROSS_COMPILE)gcc
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
INCLUDES = -I ./include -I ./uboot-headers -ffreestanding
DEFINES = -DSOC_HEADER="\"h6.h\""
ifneq ($(DEBUG),1)
DEFINES += -DNDEBUG
endif
ASFLAGS = $(INCLUDES) $(DEFINES) -D__ASSEMBLY__
CFLAGS = $(INCLUDES) $(DEFINES) -O2
LDSCRIPT = ldscripts/a64.ld
LDSCRIPTS = ldscripts/a64.ld ldscripts/common.ld
LDFLAGS = -nostdlib -nostartfiles -static -T $(LDSCRIPT)
OBJS = start.o init.o uart.o stack.o exceptions.o exception_funcs.o panic.o pgtables.o trapped_funcs.o
all: el2-bb.bin
el2-bb.elf: $(OBJS) $(LDSCRIPTS)
$(LD) $(LDFLAGS) $(OBJS) -o $#
el2-bb.bin: el2-bb.elf
$(OBJCOPY) -O binary $< $#
.PHONY: clean
clean:
rm -f el2-bb.* *.o
-nostartfiles is a gcc option but not an ld option.
If you use gcc to invoke the linker (say with LD=gcc in your Makefile) for making a standalone program that does not use standard startup files, you should use -nostartfiles because gcc links the startup files by default and -nostartfiles disables this.
ld doesn't links any startup files by default, so there is no option to disable linking them. You always pass startup files explicitly to ld. If you don't want startup files, just don't pass them to ld.
In order to see what startup files on your system are create an empty C program:
int main(){}
and compile it:
gcc -c empty.c
gcc -v empty.o
You are likely to see an invocation of ld (or perhaps of collect2, which calls ld) with a long, long list of options and object files.
Now run
gcc -nostartfiles -v empty.o
The .o files are now gone. That's exactly what -nostartfiles does.
When you invoke ld empty.o, these files and options are not there to begin with. In order to make a working program for say a Linux system, you need to pass most of them to ld explicitly. If you are building a program for something other system, you may not need some or all of them. So just don't pass them in.

Preprocessor directives in linux makefile

How do you use commands like #define and !include in linux makefile for the g++ compiler?
My understanding is that # creates a comment line so wont #define just be a comment?
Thanks for the help
I typically define a variable at the top of the file, and set it equal to the #define values I want like this:
DEFINES=-DSOMETHING -DSOMETHING_ELSE
For includes, g++ accepts search paths from the command line with -I.
For the makefile you can do the same thing, just make a variable and add the paths:
INCLUDES=-I/path -I/path2
The makefile then just calls the compiler as
g++ $(DEFINES) $(INCLUDES) file.cpp
Check out this example
# I am a comment, and I want to say that the variable CC will be
# the compiler to use.
CC=g++
# Hey!, I am comment number 2. I want to say that CFLAGS will be the
# options I'll pass to the compiler.
CFLAGS=-c -Wall
all: hello
hello: main.o factorial.o hello.o
$(CC) main.o factorial.o hello.o -o hello
main.o: main.cpp
$(CC) $(CFLAGS) main.cpp
factorial.o: factorial.cpp
$(CC) $(CFLAGS) factorial.cpp
hello.o: hello.cpp
$(CC) $(CFLAGS) hello.cpp
clean:
rm *o hello
for more information check these:
http://mrbook.org/blog/tutorials/make/
http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/makefile.html

Converting a visual studio makefile to a linux makefile

i am new to makefiles and have just rescently created a makefile that works for a c++ project. it has two cpp files and one h file. i am trying to convert my file to work in linux but cant seem to figure out how. any ideas?
EXE = NumberGuessingGame.exe
CC = cl
LD = cl
OBJ = game.obj userInterface.obj
STD_HEADERS = header.h
CFLAGS = /c
LDFLAGS = /Fe
$(EXE): $(OBJ)
$(LD) $(OBJ) $(LDFLAGS)$(EXE)
game.obj: game.cpp $(STD_HEADERS)
$(CC) game.cpp $(CFLAGS)
userInterface.obj: userInterface.cpp $(STD_HEADERS)
$(CC) userInterface.cpp $(CFLAGS)
#prepare for complete rebuild
clean:
del /q *.obj
del /q *.exe
For in depth treatment of make on Linux, see GNU make.
There are a few differences. Binaries have no extension
EXE = NumberGuessingGame
The compiler is gcc, but need not be named, because CC is built in, same goes for LD. But since your files are named .cpp, the appropriate compiler is g++, which is CXX in make.
Object files have extension .o
OBJ = game.o userInterface.o
STD_HEADERS = header.h
Compiler flags
CXXFLAGS = -c
The equivalent for /Fe is just -o, which is not specified as LDFLAGS, but spelled out on the linker command line.
Usually, you use the compiler for linking
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $(OBJ) -o $(EXE)
You don't need to specify the rules for object creation, they are built in. Just specify the dependencies
game.o: $(STD_HEADERS)
userInterface.o: $(STD_HEADERS)
del is called rm
clean:
rm -f $(OBJ)
rm -f $(EXE)
One important point is, indentation is one tab character, no spaces. If you have spaces instead, make will complain about
*** missing separator. Stop.
or some other strange error.
You can also use CMake to accomplish your task:
Put following into CMakeLists.txt file in the root directory of your project (<project-dir>):
cmake_minimum_required (VERSION 2.6)
project (NumberGuessingGame)
add_executable(NumberGuessingGame game.cpp serInterface.cpp)
Then on the console do
"in-source" build
$ cd <project-dir>
$ cmake .
$ make
or "out-source" build
$ mkdir <build-dir>
$ cd <build-dir>
$ cmake <project-dir>
$ make
You can adjust build setting using nice GUI tool. Just go to the build directory and run cmake-gui.
You don't need to include headers in the dependency list. The compiler will fail on its own, stopping make from continuing. However, if you're including them in the dependency list to force make to rebuild files in case the header changes, nobody will stop you.
CFLAGS never needs to contain -c, nor does LDFLAGS need -o. Below is a revamped makefile. Note that you can always override a macro explicitly defined in a makefile or implicitly defined using something like make CFLAGS=-Wall for example. I used the de facto standard CXX macro name in the event that you have C source files, which must be compiled using a C compiler (the value of the CC macro) instead of a C++ compiler.
.POSIX:
#CC is already implicitly defined.
CXX = g++
OBJ = game.o userInterface.o
STD_HEADERS = header.h
.SUFFIXES:
.SUFFIXES: .o .cpp .c
NumberGuessingGame: $(OBJ) $(STD_HEADERS)
$(CXX) $(CFLAGS) -o $# $(OBJ) $(LDFLAGS)
.cpp.o: $(STD_HEADERS)
$(CXX) $(CFLAGS) -c $<
#There is already an implicit .c.o rule, thus there is no need for it here.
#prepare for complete rebuild
clean:
-rm -f NumberGuessingGame *.o
As yegorich answered, you can use a build system like Cmake. It is much more flexible, cross-platform, and can generate Unix Makefiles as well as Nmake Makefiles and Visual Studio solutions on Windows.

Cannot compile with makefile - undefined reference to `boost::re_detail

I got an assignment to improve running time of some code. The only problem is, I can't even compile it to run it on my machine in the first place. Every time I try, it stops somewhere in the midst of compiling saying this:
"undefined reference to `boost::re_detail::put_mem_block(void*)'
collect2: ld returned 1 exit status make: * [cpu] Error 1"
This is how makefile looks:
SHELL = /bin/bash
OBJECTS = main.o atom.o molecule.o charges.o pdb.o asa.o amino.o chain.o addition.o string_operation.o pdb_peptide.o protein_chain.o residue_atom.o chain_residue.o residue_contact.o atom_grid.o circles.o atom_space_calculations.o
OBJDIR = obj
VPATH = src:src/ext:$(OBJDIR)
CFLAGS = -O3 -Wall -lm -lboost_regex -L/usr/local/boost/lib
HDIRS = src,src/ext,src/qt_redistributable, usr/lib, usr/local/lib, usr/local/lib/include/boost, /usr/local/lib/lib/
IOPTS = $(addprefix -I, $(HDIRS))
cpu : $(addprefix $(OBJDIR)/, $(OBJECTS) $(CPUOBJS))
g++ $(CFLAGS) -o mcpu $^
$(OBJDIR)/%.o : %.cpp
g++ $(CFLAGS) $(IOPTS) -c $< -o $#
clean :
rm obj/*.o $(PROG)
I'm using Linux Mint x64 and I have tried everything I googled out. Installed the whole boost library in usr/local/lib (for no obvious reason because it didn't help), tried to edit LD PATH (I'm very new to Linux and I have no idea if that went right) and lots of stuff, but this thing doesn't seem to go through. Any help appreciated.
One problem with your makefile happens when you link your program. As you can see in these questions with g++ the order of your arguments at link time is really important. You need to put your libraries after your object files. One easy way to solve would be separating your linker flags (LDFLAGS) from the compiler flags (CFLAGS), and then putting LDFLAGS after $^ (your object files) in the link command.
CFLAGS = -O3 -Wall
LDFLAGS = -L/usr/local/boost/lib -lm -lboost_regex
cpu : $(addprefix $(OBJDIR)/, $(OBJECTS) $(CPUOBJS))
g++ $(CFLAGS) -o mcpu $^ $(LDFLAGS)
$(OBJDIR)/%.o : %.cpp
g++ $(CFLAGS) $(IOPTS) -c $< -o $#
As can be seen in the Catalogue of Built-In Rules:
Linking a single object file
n is made automatically from n.o by running the linker (usually called
ld) via the C compiler. The precise recipe used is:
$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
and Variables Used by Implicit Rules:
LDFLAGS
Extra flags to give to compilers when they are supposed to invoke the linker,
ld, such as -L. Libraries (-lfoo) should be added to the LDLIBS variable
instead.
So in this case -lboost_regex should be set or added to LDLIBS, not LDFLAGS.

Setting Variables within Makefile commands

I'm facing a silly problem with GNU makefile.
I want to define two targets to build a c program; one with debugging and the other without.
runNoDebug: setNoDeb objs runMe
runDebug: setDeb objs runMe
setNoDeb:
{EXPORT} MyDEBUG= -O3
setDeb:
{EXPORT} MyDEBUG="-DDEBUG=1 -g"
objs: cFiles
$(CC) -o $# $^ $(cFiles) $(CFLAGS) $(LIBS) $(MYDEBUG)
runme: objs
./oo
Errors arise on running this makefile, the command to set debugging executes on the subshell causing errors. If "Export" is added, the variable is defined in that subshell.
I want to define this variable in the makefile iteself to be used while building objects.
Is it possible? Or should I duplicate the "objs: cFiles" target?
You need target-specific variable values :
This feature allows you to define different values for the same variable, based on the target that make is currently building.
runNoDebug: setNoDeb runMe
runDebug: setDeb runMe
setNoDeb: CFLAGS += -O3
setNoDeb: objs
setDeb: CPPFLAGS += -DDEBUG=1
setDeb: CFLAGS += -g
setDeb: objs
objs: $(cFiles)
$(CC) $(CFLAGS) $^ $(LIBS) -o $#

Resources