arm-non-eabi-ld: Argument list too long - gcc

I'm trying to resolve an issue with my project. In short, I have a variable in my makefile containing the names of .o files to be linked. The variable has gotten too big, and is now causing an Argument list too long error. The offending line in my makefile reads:
#arm-none-eabi-ld -T layout.ld -o #$ $^
The problem is the variable $^ expands to be too large, and I get an error stating that "arm-none-eabi-ld: Argument list too long".
What I'm trying to do to resolve the issue is to pass the arguments as a file, but I'm not sure how.
What I've tried is:
#arm-none-eabi-ld -T layout.ld -o #$ <$^
#arm-none-eabi-ld -T layout.ld -o #$ | xargs `cat $^`
and also tried:
#echo $^ >temp.txt
#arm-none-eabi-ld -T layout.ld -o #$ <temp.txt
that last one I think has potential, but says "no input files".

I found a solution:
#echo "INPUT($^)" > $(TEMP_LD)
#$(LD) $(LDFLAGS) -o $# -T $(TEMP_LD)

Related

problems with kernel not being loaded

I'm creating an OS and when I compile the code nothing happened, simply nothing(No errors, warnings or anything) I"m thinking that the make file has some issues.
Makefile:
build_kernel:
echo "Building kernel..."
${ASM} ./src/kernel/kernel_entry.asm -f elf64 -o ${BUILD_DIR}/kernel_entry.o
${C_COMPILER} -c ./src/kernel/kernel.c -o ${BUILD_DIR}/kernel_start.o
${C_COMPILER} -c ./src/kernel/drivers/printutils.c -o ${BUILD_DIR}/kernel_printutils.o
${C_COMPILER} -c ./src/kernel/drivers/port.c -o ${BUILD_DIR}/kernel_ports.o
echo "kernel build complete."
link:
echo "Linking..."
${LINKER} -o ${BUILD_DIR}/kernel.bin ${BUILD_DIR}/kernel_ports.o \
${BUILD_DIR}/kernel_printutils.o ${BUILD_DIR}/kernel_start.o \
${BUILD_DIR}/kernel_entry.o -Ttext 0x1000 --oformat binary
echo "Linking complete"
run:
echo "Running qemu..."
qemu-system-x86_64 -fda ${BUILD_DIR}/os.bin
merge_binary:
echo "Merging binary..."
cat ${BUILD_DIR}/boot.bin ${BUILD_DIR}/kernel.bin > ${BUILD_DIR}/os.bin
echo "Binary merged."
post_build:
rm -f ${BUILD_DIR}/boot.bin
rm -f ${BUILD_DIR}/kernel.bin
rm -f ${BUILD_DIR}/kernel.o
rm -f ${BUILD_DIR}/kernel_entry.o
rm -f ${BUILD_DIR}/kernel_ports.o
rm -f ${BUILD_DIR}/kernel_printutils.o
rm -f ${BUILD_DIR}/kernel_start.o
I'm wondering what is happening with the makefile and is this the correct way to compile all the code into object files and link them.
Any help will be appreciated.
I'm just commenting on your make style -- this does not answer why you are outputting nothing (and it is unclear what you mean by that -- if you run make, it should output at least echo "Building kernel..."...). As far as the makefile style goes, this seems to be built using a scripting mentality rather than a make mentality. Consider your first part:
build_kernel:
echo "Building kernel..."
${ASM} ./src/kernel/kernel_entry.asm -f elf64 -o ${BUILD_DIR}/kernel_entry.o
${C_COMPILER} -c ./src/kernel/kernel.c -o ${BUILD_DIR}/kernel_start.o
${C_COMPILER} -c ./src/kernel/drivers/printutils.c -o ${BUILD_DIR}/kernel_printutils.o
${C_COMPILER} -c ./src/kernel/drivers/port.c -o ${BUILD_DIR}/kernel_ports.o
echo "kernel build complete."
This has several issues. First is the name -- this looks to build a bunch of artifacts rather than building the kernel. Also, the recipe never produces a file named build_kernel, thus this should have been a phony target. Next, this is actually a script, which builds four separate things. These could be separated out into four separate rules, each which builds one thing, and then the main target would be dependent on this. Thus, it might look like:
.PHONY: build_kernel_objs
build_kernel_objs: ${C_OBJS} ${ASM_OBJS}
#echo done building $#
${BUILD_DIR}/kernel_start.o : ./src/kernel/kernel.c
${C_COMPILER} -c $< -o $#
${BUILD_DIR}/kernel_printutils.o : ./src/kernel/kernel_printutils.c
${C_COMPILER} -c $< -o $#
${BUILD_DIR}/kernel_ports.o : ./src/kernel/kernel_ports.c
${C_COMPILER} -c $< -o $#
Note that the above is repetitive, and if you have hundreds of files, will bolat very quickly. This can also be done using static pattern rules:
C_FILES := \
./src/kernel/kernel_start.c
./src/kernel/kernel_printutils.c
./src/kernel/kernel_ports.c
ASM_FILES := \
./src/kernel/kernel_entry.asm
C_OBJS := ${C_FILES :./src/kernel/%.c=${BUILD_DIR}/%.o}
ASM_OBJS := ${ASM_FILES :./src/kernel/%.asm=${BUILD_DIR}/%.o}
${C_OBJS} : ${BUILD_DIR}/%.o : ./src/kernel/%.c
${C_COMPILER} -c $< $#
.PHONY: build_kernel_objs
build_kernel_objs: ${C_OBJS} ${ASM_OBJS}
#echo "done building $#"
These have several advantages over what you've done -- first, make will only ever build the objects that are out of date, so it doesn't do needless work. It can also build the files in parallel if a -j option is specified on the make command line. Next, it's more maintainable -- if you have to add extra files, you can do it in one place, and everything works out. Also, the .PHONY prevents the make from failing if you happen to have a file named build_kernel_objs in your make directory. Lastly, the # in front of the echo lines prevents the actual echo command from being echoed, which will look nicer.
On caveat to this is that it does not handle modification of header files (as written, if a header file is updated, c files that depend on it would not be rebuilt. See here for some notes about getting around that.
The next section, link, the makefile recipe should reflect the target.
.PHONY: link
link : ${BUILD_DIR}/kernel.bin
${BUILD_DIR}/kernel.bin: ${C_OBJS} ${ASM_OBJS}
${LINKER} -o $# $^ -Ttext 0x1000 --oformat binary
This creates a phony target link, so you can type make link. It will only do the link if any of the C objects or ASM objects have been updated. The same concept applies to your merge_binary target
For run, this seems to be somewhat contentious, but a common rule of thumb is that a make should be used to make an executable, not to run it. A separate shell script is better suited if you want to invoke your built target with specific parameters.
Lastly, your post_build rule should likely be renamed to CLEAN, and declared as a phony.

How to compile a test snippet nicely with gnu make?

I don't have a configure stage in my baseline (for various reasons), but I need to check whether my C compiler can support the -mavx2 flag or not.
If I have an empty file, call it test.cc then I can do something like:
$(CC) -mavx2 -c test.cc -o test.o
And check the return status code. Obviously I don't want to leave those test.* files lying around though, but can't think of a good way to generate/test/delete them outside of a recipe. Does anyone know of a good pattern to do this?
Or, you could just take input from stdin, and output to /dev/null:
SUPPORTS_MAVX2:=$(shell echo 'void main(){}' | \
gcc -x c -maxv3 -o /dev/null - 2>/dev/null; \
echo $$?)
Then there are no artifact files to be deleted. The -x c is necessary to tell gcc what language it is (as it can't determine that from the filename in this case), and you need the trailing - as well.
Turns out you can use "eval" to remove the temporary file and return the status code, so this works:
AVX2 = $(shell touch test.cc; $(CC) -mavx2 -c test.cc -o /dev/null >& /dev/null; eval "rm -f test.cc; echo $$?")
Edit and without the temporary file (assuming a sane system):
AVX2 = $(shell $(CC) -mavx2 -c /usr/include/stdlib.h -o /dev/null >& /dev/null; echo $?)

How is this complex generic Makefile rule constructed

Several modules each are tested independently with their own test_$(MODULE).c.
A shared library has been generated $(LIBRARY) containing modules without coverage. $(basename $<).o should override the one in $(LIBRARY). For some reason, I get results as if they are not overridden. Can someone review this and make suggestions on fixes? Currently I have non-generic gcov rules for each of the five objects. These gcovs work correctly. Below I show the generic rule and one specific use of the rule.
SHARED_OPTS=-O0 -Wall -Wextra -fPIC
GOPTS=$(SHARED_OPTS) -g -coverage -pg
%.gcov : %
#echo "\t$# generic (needs work)"
#-gcc $(GOPTS) -c -o test_$(basename $<).o test_$<
#-gcc $(GOPTS) -c -o $(basename $<).o $<
#-gcc $(GOPTS) -o gcov_test_$(basename $<) \
test_$(basename $<).o \
$(basename $<).o \
-L . -l $(LIBRARY)
#-./gcov_test_$(basename $<)
#-gcov $< >$#.out 2>&1
#echo "no Mac gprof: -gprof gcov_test_$(basename $<) gmon.out > $<.prof"
#$(call timestamp,$#)
Unicode.c.gcov: Unicode.c
If anyone is interested in collaborating on high efficiency high quality Unicode lexing/parsing support by developing a shared library, I would love to have reviewers or contributors.
The Makefile fragment shown above is in a github repository:
https://github.com/jlettvin/Unicode Specifically down the c subdirectory.
While you're trying to find problems in your makefile you should avoid using #, as it hides the command line and so you can't see issues. Also you should avoid - here: if any of those commands fail you certainly don't want to continue to run the rest of the recipe, I wouldn't expect.
I don't know if it's a cut/paste problem but I have to assume that these lines, at least, are wrong:
#-gcc $(GOPTS) -c -o test_$(basename $<).o test_$<
#-gcc $(GOPTS) -c -o $(basename $<).o $<
As far as I can tell from your makefile, the last words on these lines should be test_$<.c and $<.c respectively.

Compilation errors with Make File creation

While running my make file which is as follows,
../bin/output : ../lib/libfun.a ../obj/main.o
gcc ../main.o -L ../lib/ -lfun -o $#
../lib/libfun.a : ../obj/file_write.o ../obj/error.o
ar -rc $# $^
../obj/main.o : ../src/main.c
gcc -c $^ -o $# -I ../include
../obj/file_write.o : ../src/file_write.c
gcc -c $^ -o $# -I ../include
../obj/error.o : ../src/error.c
gcc -c $^ -o $# -I ../include
I am getting error like
make: Warning: File `makefile' has modification time 2.2e+03 s in the future
ar -rc ../lib/libfun.a ../obj/file_write.o ../obj/error.o
ar: ../lib/libfun.a: No such file or directory
make: *** [../lib/libfun.a] Error 1
and sometimes
"* missing separator (did you mean TAB instead of 8 spaces?). Stop"
Why is this happening? I gave correct Target,Pre-Requests and Command values whichever needed. Whats wrong in this?
For the first error, make sure the ../lib directory exists before trying to create a library in it. ar will return that error if the path doesn't exist.
For the second make syntax is strict: the commands after a target must be indented with a tab, not spaces.
target: deps
command
# ^ this here needs to be a tab character, not spaces

Getting Quiet Make to echo command lines on error

I have a Makefile building many C files with long long command lines and we've cleaned up the output by having rules such as:
.c${MT}.doj:
#echo "Compiling $<";\
$(COMPILER) $(COPTS) -c -o $# $<
Now this is great as the # suppresses the compilation line being emitted.
But when we get an error, all we get is the error message, no command line.
Can anyone think of a "neat" way to emit the command line?
All I can think of doing is echoing it to a file and have a higher level make catch the error and cat the file. Hacky I know.
Tested and it worked (GNU make in Linux):
.c${MT}.doj:
#echo "Compiling $<";\
$(COMPILER) $(COPTS) -c -o $# $< \
|| echo "Error in command: $(COMPILER) $(COPTS) -c -o $# $<" \
&& false
This question is pretty old, but for those of you Googling, I think what I’ll do in this situation is alias make to make -s (silent mode) in my shell, and only put the # prefix before lines where echo or other diagnostic commands are being invoked. When I want the full output from make, I will override my alias by calling it as \make.
Also note that in this situation that you’ll need to do the typical thing and put the #echo on its own line, with the actual rule commands on separate lines and without #’s.
A simple solution would be to use a simple script abc like the following:
#!/bin/bash
$#
code=$?
if (( code )); then
echo error running $#
fi
exit $code
Then you can write abc $(COMPILER) $(COPTS) -c -o $# $< in your Makefile. Do note that this does not work when you have pipes or redirects (as they will be applied to abc instead of the command you want to run).
You can also just put similar code directly in the Makefile if that's preferable.
I recently used a utility called logtext for the likes of tracking what output had occurred during the course of a bat file executing. Check it out, you may find this pretty useful if you want to know what error occurred where.

Resources