nmake makefile, linking objects files in a subfolder - makefile

My makefile defines a link command:
prod_link = $(LINK) $(LINK_FLAGS) -o$(PROD_OUT) $(PROD_OBJS)
where $(PROD_OBJS) is a list of object files of the form:
PROD_OBJS = objfile1.obj objfile2.obj objfile3.obj ... objfileN.obj
Now the makefile itself is at the root of my project directory.
It gets messy to have object and listing files at the root, I'd like to put them in a subfolder.
Building and outputing the obj files to a subfolder works, I'm doing it with suffixes and inference:
.s.obj:
$(ASSEMBLY) $(FLAGS) $*.s -o Objects\$*.obj
The problem is to pass the Objects folder to the link command.
I tried:
prod_link = $(LINK) $(LINK_FLAGS) -o$(PROD_OUT) Objects\$(PROD_OBJS)
but only the first file in the list of object files gets the folder's name.
How can I pass the Objects subfolder to all files of my list $(PROD_OBJS)?
EDIT
I tried also
PROD_OBJS = $(patsubst %.ss,Object\%.obj, $(PROD_SRC))
but got:
makefile(51) : fatal error U1000: syntax error : ')' missing in macro invocation
Stop.
This is quite strange...

nmake is not GNUMake, and is rather rubbish. See the NMAKE Reference for details.
As far as your problem goes (translating 1.o 2.o 3.o into d/1.o d/2/o d/3.o), try
OBJS= 1.o 2.o 3.o
# Looks wierd I know, but basically change ' ' to ' d/'
# (and it's not very robust!)
OBJS_WITH_PREFIX= d/$(OBJS: = d/)
!ERROR [$(OBJS_WITH_PREFIX)]
By the way, your pattern rule is lying to nmake. You say .s.obj:, which says "here is how to convert a .s file into a .obj," but then the commands you give actually create the object in a subfolder. You should have started the pattern rule with .s{Objects\}.obj:. See the docs for more details (Search Paths in Rules).

Very late to the party, but in case anyone else runs into the same problem:
This error
makefile(51) : fatal error U1000: syntax error : ')' missing in macro invocation
Stop.
is caused by the fact that the patsubst syntax doesn't seem to be supported by nmake. You can get around this by using the alternative syntax
$(var:suffix=replacement)
instead of
$(patsubst %suffix,%replacement,$(var))
(this is also valid in gnumake).

Related

What Makefile rule is appending .c to a missing include?

In a makefile, there is a statement:
include $(PROJECT_CUSTOM_DIR)/project_custom.mak
In some cases, this file will not exist. In those cases, we get the error saying "no such file or directory". However, it appears that an implicit rule (or something), appends the extension .c which then matches one of our standard rules for compiling .c to .o files, and it tries to compile it.
Our default rule for .c files looks like this:
PROJECT_CUSTOM_DIR := .
include $(PROJECT_CUSTOM_DIR)/project_custom.mak
C_EXT ?= c
CXX_EXT ?= cpp
OBJ_EXT ?= o
%.$(OBJ_EXT) : $(C_SRCS)
$(COMPILE_C_COMMAND)
The error from the log is here:
Makefile:10: project_custom.mak: No such file or directory
gcc -c -fvisibility=hidden -O3 -flto -mtune=generic project_custom.mak.c -o project_custom.mak.o
I've read quite a lot trying to determine what is happening here and am stumped. Can anyone explain this behavior?
Also, I am aware of that adding a dash such as -include file.mak suppresses the error about the file not being found. Also, disabling implicit rules is not an option here.
Thanks!
Based on comments, I've now run make with debugging. I found that Make is doing normal/expected evaluation of all files that are included with include(file). The implicit rules for included files is to try to rebuild them if they do not exist. Since this is not what I wanted, I used the following empty explicit rule to override the behavior, and do nothing for all my included files. This was easy in my case because they all share the .mak extension. Here is the rule:
%.mak : ;
Thanks to those who added feedback.

Link command line too long: how to use response files when linking in scons on windows

Like others I have a link line that exceeds the Windows cmd line limit. For most cases we have solved the problem by building intermediate archives (aka static libraries) with subsets of the object files and performed the final link with those archives. However using this strategy with Google Test this causes the tests not to be found, specifically the tests defined in the object files that were archived.
Update: This is why. I will probably use this workaround, but I would still like to understand how to make response files work under scons.
The LongCmdLinesOnWin32 fix is problematic. We have a cygwin environment and pathnames that include spaces, so some compiler absolute paths involve quotes. The script in LongCmdLinesOnWin32 first needs to be extended to handle both the embedded quotes and the spaces (otherwise it creates separate tokens of a single path name). More seriously, when using MS Visual Studio, the compiler command is just 'cl' i.e doesn't include the pathname. This is not available in the PATH environment--it appears to be dynamically set (somehow) and not visible when constructing the cmdline argument to the LongCmdLinesOnWin32 script. But I digress....
There seems to be a much simpler (and to my eyes suitable) solution: response files, which are also supported by gcc.
I wrote a little function to take the list of object names and print them to a text file, one to a line, something like:
"""
In place for generating response files
"""
def gen_response_file(filename,file_list):
with open(filename,"w") as f:
for obj_name in file_list:
f.write ('%s\n' %os.path.abspath(str(obj_name)).replace('\\','/'))
return filename
I then tried prepending the '#' character to the file name and added it to the list of options.
The command line echoed was:
link /nologo /MACHINE:x86 /DEBUG #E:\dev\pcoip_view_client\soft_test.rsp /OUT:blah_client\blah_client_tests.exe /LIBPATH:\\sterbkp03\qt\4.8.2\lib ....
If I simply named the file "soft_test" then scons would add the suffix ".obj" and the linker could not find it, so I tried adding the suffix '.rsp'. Now, the linker complains it cannot find the file, but it is present. I captured the output from scons and pasted it to a bat file. When I ran the bat file (from the VS 2008 command line env.) the link worked like a charm, so it seems like scons is somehow causing the problem with finding the file
I tried changing the path, using absolute (#C:\blah\soft_test.rsp), relative (#.\soft_test.rsp) and just #soft_test.rsp, none of them worked.
LINK : fatal error LNK1104: cannot open file '#E:\dev\swift.dev\blah_client\soft_test.rsp'
scons: *** [blah_client\blah_client_tests.exe] Error 1104
I'm using scons v2.1.0.r5357, VS 2008 and python 2.7 under Windows 7-64
My scons file looks like:
test_objects = tenv.Object(test_sources)
xx = gen_response_file('soft_test.rsp',test_objects)
tenv.Append( LINKFLAGS = [ '#%s' % os.path.abspath(xx)]) #
test_exe = tenv.Program(target = 'blah_client_tests', source = objects + moc_objects + qrc_objects )
Any suggestions greatly appreciated.
Update: I tried with gcc and there was no problem. My guess is that somehow the scons rules associated with Visual Studio tools is different enough to cause grief.
I tried to reproduce this in Linux using gcc, and came across a different problem, whose solution may help.
Originally, I used this SConscript:
import os
"""
In place for generating response files
"""
def gen_response_file(filename,file_list):
with open(filename,"w") as f:
for obj_name in file_list:
f.write ('%s\n' %os.path.abspath(str(obj_name)).replace('\\','/'))
return filename
env = Environment()
test_objects = env.Object(target = 'testClass', source = 'testClass.cc')
resp_file = gen_response_file('response_file.rsp', test_objects)
env.Append(LINKFLAGS = [ '#%s' % os.path.abspath(resp_file)])
env.Program(target = 'helloWorld', source = 'helloWorld.cc')
Here are the related source files I used:
# tree .
.
|-- SConstruct
|-- helloWorld.cc
|-- testClass.cc
`-- testClass.h
Where helloWorld.cc is the main program. helloWorld.cc includes testClass.h and links in testClass.o When I tried to compile this, the response file was correctly generated (only contains /some/path/testClass.o) and read by the compiler. The problem that I came across was that testClass.o was not compiled, since SCons doesnt appear to recognize the dependency with the objects listed in the response file. Here is the result:
# scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o helloWorld.o -c helloWorld.cc
g++ -o helloWorld #/some/path/response_file.rsp helloWorld.o
g++: /some/path/testClass.o: No such file or directory
scons: *** [helloWorld] Error 1
scons: building terminated because of errors.
This seems like a failure in SCons because it doesnt analyze the response file. To solve this problem, I had to use the Depends() function as in the following excerpt:
...
bin = env.Program(target = 'helloWorld', source = 'helloWorld.cc')
env.Depends(bin, test_objects)
This worked and gave me the following:
# scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o helloWorld.o -c helloWorld.cc
g++ -o testClass.o -c testClass.cc
g++ -o helloWorld #/some/path/response_file.rsp helloWorld.o
scons: done building targets.
I know this doesnt answer the original question about why the response files cant be found, but once you solve that, you will most likely run into the problem mentioned above, and have to use the Depends() function.

make giving error after make clean

Although Make is working fine but by default it only compiling those files that have been changed, even when I run make all. It say like Nothing to Do.
One scenario where I neeed to compile all the files is when I change something in a header file which is being accessed in multiple .c files. But make does not recognize it until I open any .c file any save & quit again.
Makefile contents can be seen in this post :
Questions about Makefile - what is "$+" & where are .c files/dependencies called here ?
Although this is also a problem but actual problem I want to discuss here is something different.
In order to compile all files what I did was that I ran make clean which indeed removed all object files and then I ran make again but this time it gives an error :-
....
mec/gen_crc32table > mec/crc32table.h
mec/gen_crc32table: 1: mec/gen_crc32table: Syntax error: end of file unexpected
(expecting ")")
make: *** [mec/crc32table.h] Error 2
I checked contents of crc32table.h but file is empty. So, I copy crc32table.h from my backup of previous code and now its running successfully. Now I run make clean and 'make' again to check it but this time it is working fine.
I do not know what the mystery here ?
I guess these lines are doing something which I am not able to understand ? Please help me on this.
crc32.o: mec/crc32table.h mec/crc32.c
$(CC) -o $# -c -I. $(CFLAGS) mec/crc32.c
mec/crc32table.h: mec/gen_crc32table
mec/gen_crc32table > mec/crc32table.h
The issue is this snippet:
mec/crc32table.h: mec/gen_crc32table
mec/gen_crc32table > mec/crc32table.h
Ask yourself "What happens if the gen_crc32table command exits with an error?" Make stops (good) but leaves behind a corrupt crc32table.h (bad). Two choices: (i) re-write gen_crc32table so that it accepts a -o parameter; (ii) shell trickery.
(i)
mec/crc32table.h: mec/gen_crc32table
mec/gen_crc32table -o mec/crc32table.h
(ii)
mec/crc32table.h: mec/gen_crc32table
mec/gen_crc32table >temp-file-with-an-obscure-name
mv temp-file-with-an-obscure-name $#
The mv will not happen if gen_crc32table errors.

Make error of mixed implicit and normal rules

When building an open source project I met error of:
make subdir=manual -C manual ..=../ subdir_lib
Makefile:235: *** mixed implicit and normal rules. Stop.
Code from line 235 of the Makefile as follows:
235: $(objpfx)stubs ../po/manual.pot $(objpfx)stamp%:
236: $(make-target-directory)
237: touch $#
That error message is printed by GNU make when you have something that looks like a pattern rule output (containing a %) as well as something that looks like a normal output (no %) on the left-hand side of a : in a rule declaration. For example:
%.pat normal:
#echo $#
So on line 235 of your Makefile, you have managed to put together something that "looks like" that construct. To avoid the error, fix that declaration, most likely by splitting it into two:
%.pat:
#echo $#
normal:
#echo $#
Without seeing the complete makefile that produced this error there's not much more advice we can give you.
I am here to remind the successor, check your path, is there any space in it?
We wasted all afternoon on this!
In my case, the error was due to idiotically putting an extraneous : at the end of the dependency line:
%.o: %.cpp:
g++ -c -o %# $<
Just had this myself and it was due to a hidden space after a "/" in a variable definition i.e.
#accidental/invisible space left after the final "/" i.e...
DESTDIR=path/to/the/destination/directory/
# ...just here ^
#rule to make copies of text files...
$(DESTDIR)%.txt:$(SRCDIR)%.txt
The problem described in this question has been reported here
http://sourceware.org/bugzilla/show_bug.cgi?id=11873
The fix was indeed to split the rule, as suggested by Eric.
Completing Eric Melski answer, you can do this to avoid duplicating code everywhere:
define DEFAULTTARGET :=
#echo $#
endef
%.pat:
${DEFAULTTARGET}
normal:
${DEFAULTTARGET}
Check your path, check where you have saved your projects, there shouldn't be a space in the name of the directory. Save it along with system generated projects directory files if u have imported it from another source
maybe you have "space" character after path.
for example:
(this is a ' ' character at the end)
PATH_OUT = ../lib
then you use
$(PATH_OUT)/1.cc
and you will get this error

How to write rule to build object file when C files have different paths

I have bunch of C files, each with differnt path, so I have something like
SRC=/path1/path2/file1.c file2.c /usr/joe/files/file3.c
I want to build object file from each C file in build directory, so I did:
SRCBASE=$(notdir $(SRC))
OBJS= $(addprefix $(OBJDIR)/,$(SRCBASE:.c=.o))
This works fine, and I got the OBJS is build/file1.o build/file2.o build/file3.o
My question is how to write the implicit rule to build the object file, I tried to do:
build/%.o : %.c
gcc ....
But that seems now to work, since this rule did not catch the files with the full path.
I've tried to look at the gnu make, but did not find the answer there.
Many thanks.
You can use VPATH to locate files in other directories. Note that this does implicit searches, though, rather than using explicit paths. That is, you specify that you need file1.o through file3.o and that make should look first in ., then in /path1/path2, then in /usr/joe/files; so if . contains a file3.c you will get that one rather than the one in /usr/joe/files (or if not, but if there is one in /path1/path2, you will get that one).
It turns out that path searching is more often useful than explicit location anyway, so usually that's what you want. If you need to override something you just copy or symlink the "desired version" to the first place to be searched.

Resources