gcc makefile dependency wont generate - gcc

I have the following simple makefile
#all: binsem.a ut.a ph
FLAGS = -Wall -L./
binsem.a:
gcc $(FLAGS) -c binsem.c
ar rcu libbinsem.a binsem.o
ranlib libbinsem.a
ut.a:
gcc $(FLAGS) -c ut.c
ar rcu libut.a ut.o
ranlib libut.a
clean:
rm -f *.o
rm -f a.out
rm -f *~
rm -f ph
rm -f *a
The problem is it only generates binsem.a and not ut.a, probably because of dependencies issues.
I tried looking at the flags but did not find the answer.
Thanks a lot.

By default, if you don't specify a target on the command line, make will build the first target it finds (and it's dependencies if it has any). Your first target is binsem.a, and you don't list any dependencies, so that's the only thing that gets built.
Try something like adding this at the top:
all: binsem.a ut.a
And mention the dependencies in your other targets:
binsem.a: binsem.c
...
ut.a: ut.c

Related

GCC ERROR: Cannot Execute Binary File [GCC Compiled from Source]

I am writing an Operating System. I am currently stuck at not being able to compile C code into output files, then further linking them with ld
When I run my make file, this error pops up:
/usr/local/i386elfgcc/bin/i386-elf-gcc -g -ffreestanding -c kernel/kernel.c -o kernel/kernel.o
/usr/local/i386elfgcc/bin/i386-elf-gcc: /usr/local/i386elfgcc/bin/i386-elf-gcc: cannot execute binary file
make: *** [kernel/kernel.o] Error 126
This is the makefile
C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)
# Nice syntax for file extension replacement
OBJ = ${C_SOURCES:.c=.o}
# Change this if your cross-compiler is somewhere else
CC = /usr/local/i386elfgcc/bin/i386-elf-gcc
GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb
LD = /usr/local/i386elfgcc/bin/i386-elf-ld
# -g: Use debugging symbols in gcc
CFLAGS = -g
# First rule is run by default
os-image.bin: boot/boot.bin kernel.bin
cat $^ > os-image.bin
# '--oformat binary' deletes all symbols as a collateral, so we don't need
# to 'strip' them manually on this case
kernel.bin: boot/kernelStart32.o ${OBJ}
${LD} -o $# -Ttext 0x1000 $^ --oformat binary
# Used for debugging purposes
kernel.elf: boot/boot_32bit_kernel_entry.o ${OBJ}
${LD} -o $# -Ttext 0x1000 $^
run: os-image.bin
qemu-system-i386 -fda os-image.bin
# Open the connection to qemu and load our kernel-object file with symbols
debug: os-image.bin kernel.elf
qemu-system-i386 -s -fda os-image.bin &
${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"
# Generic rules for wildcards
# To make an object, always compile from its .c
%.o: %.c ${HEADERS}
${CC} ${CFLAGS} -ffreestanding -c $< -o $#
%.o: %.asm
nasm $< -f elf -o $#
%.bin: %.asm
nasm $< -f bin -o $#
clean:
rm -rf *.bin *.dis *.o os-image.bin *.elf
rm -rf kernel/*.o boot/*.bin drivers/*.o boot/*.o
I have built GCC etc to the path: /usr/local/i386-elf-gcc
I am on macOS Monterey 12.4 (Intel - x86_64) and have all dependencies installed
I have tried looking everywhere for this problem, trying different flags and everything, however the problem still persisted
It means that the compiler you built doesn't run on the system you are running it on. You have to decide whether you want to do native compiling in which case you would build a compiler that runs on the target and also generates output for the target. This is how the compilers you usually use always work.
If you create that kind of compiler then you have to run make on the target since that's where you build the compiler to run.
Or, you can create a cross-compiler. A cross-compiler runs on your local system, but builds output that runs on the target system.
In your case, if you want to compile code on your MacOS system but generate binary files that run on a different system, you need a cross-compiler.

Makefile: Circular - Dependency dropped

I have designed a Makefile that compiles all the .c files individually and produces a .o respectively (I think this happens Implicitly and works perfectly fine).
The executable (.out) is not being generated from the .o files.
Makefile:
TARGET = all.out
OBJS = file1.o file2.o file3.o
CC = gcc
CFLAGS = -g -Wall
all : $(TARGET)
$(TARGET) : $(OBJS)
# gcc $^ -o $#
run : $(TARGET)
./$<
clean :
rm -rf *.o $(TARGET)
Output:
$ make
make: Circular all.out <- all dependency dropped.
gcc -g -Wall -c -o file1.o file1.c
gcc -g -Wall -c -o file2.o file2.c
gcc -g -Wall -c -o file3.o file3.c
cp file1.o all.out
Note: The Makefile works perfectly and produces the perfect results if the line no. 7 present in it is uncommented.
line no. 7:
# gcc $^ -o $#
Output when line no. 7 is uncommented (Works perfectly as intended):
gcc -g -Wall -c -o file1.o file1.c
gcc -g -Wall -c -o file2.o file2.c
gcc -g -Wall -c -o file3.o file3.c
gcc file1.o file2.o file3.o -o a.out
I am new to Makefiles.
Queries:
why does commenting line no. 7 causing this issue and uncommenting it works perfectly?
What is cp in the first output when line no.7 was commented?
What does circular - dependency dropped mean?
I can't explain how you are seeing the problem you showed to us. Either what you wrote above is not actually what you're using, or you have a buggy version of GNU make. I can't reproduce the behavior you're seeing.
But, I'm sure it's related to this: GNU make has a built-in rule that knows how to build an xx.out file from a file xx for any xx:
# make -p -f/dev/null
...
%.out: %
# recipe to execute (built-in):
#rm -f $#
cp $< $#
If you comment out your own recipe as an explicit rule, then make will search for one among the pattern rules it knows about and it will find this built-in pattern rule.
However this rule shouldn't match based on what you've shown us: in order for it to match with a target of a.out, make would have to find or know how to build a target a and that doesn't seem to be available. Also, knowing how to build a would show a circular dependency on a.out.
If your makefile was:
TARGET = all.out
THEN it would all make perfect sense because you would have:
all : all.out
all.out : file1.o file2.o file3.o
and after the implicit rule match %.out: % it would expand like this:
all : all.out
all.out : all file1.o file2.o file3.o
#rm -f all.out
cp all all.out
So I assume that when you copied the output into your question you changed it: best to not do that. You should post exactly the problem you have (and verify you still have the problem with what you posted).

Simple makefile command not found

I was given a makefile that looks like this, and told not to change it.
all: clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp clean: rm -f lex.yy.c rm -f parser.tab.*pp rm -f hw2
I am trying to run this makefile in a folder with files named: scanner.lex, parser.ypp, output.hpp and output.cpp
I copied it to a file like this:
all:
clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp
clean:
rm -f lex.yy.c rm -f parser.tab.*pp rm -f hw2
When I run the make command in my terminal I get an error:
clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp
/bin/sh: clean: command not found
make: *** [all] Error 127
Am I doing something wrong? Again, I was given this line and told not to change it.
Thanks a lot.
Line breaks are essential in most computer environments. If you were given a Makefile without the line breaks and you try to cut it randomly you will have difficulties before if finally works. Try this, maybe:
all: clean
flex scanner.lex
bison -d parser.ypp
g++ -std=c++11 -o hw2 *.c *.cpp
clean:
rm -f lex.yy.c
rm -f parser.tab.*pp
rm -f hw2
And use tabs to indent the indented lines, not spaces.
Explanations: all and clean are what is called a target in make parlance. They are the names of the things you want make to do. clean to delete some files, all to do everything else. The
target: prerequisite1 prerequisite2...
recipe1
recipe2
...
template is the basic make template. It means that target depends on prerequisite1, prerequisite2 and that in order to build it make shall pass recipe1 to the shell for execution, then recipe2...
Note that this Makefile is poorly written. As all and clean are not real file names they should be declared as phony, such that, if a file with that name exists make does the job anyway. As is, it wouldn't. Give it a try:
$ make all
$ touch clean
$ make clean
make: 'clean' is up to date.
See? Because a file named clean exists you cannot make clean anymore, make considers that there is nothing to do for clean. Add this at the beginning of your Makefile:
.PHONY: all clean
A second issue is that make works by comparing last modification times of targets and prerequisites to decide if targets must be rebuilt or not. With your Makefile make will always recompile everything, even if the inputs did not change and the outputs are up-to-date. This is a waste. A better (but untested) Makefile would be something like:
.PHONY: all clean
CFILES := $(filter-out lex.yy.c,$(wildcard *.c))
CPPFILES := $(filter-out parser.tab.cpp,$(wildcard *.cpp))
all: hw2
hw2: lex.yy.c parser.tab.cpp $(CFILES) $(CPPFILES)
g++ -std=c++11 -o $# $^
lex.yy.c: scanner.lex
flex $<
parser.tab.cpp: parser.ypp
bison -d $<
clean:
rm -f lex.yy.c
rm -f parser.tab.*pp
rm -f hw2
Understanding it and why it is better is left as an exercise.

Two targets with no dependencies

Consider the following makefile:
TARGET=fmake
TARGET2=test_second
fmake: $(TARGET2).c foo.c\
$(TARGET).c test.h clean
$(CC) -o $(TARGET) $(TARGET).c foo.c
$(CC) -o $(TARGET2) $(TARGET2).c
foo.c:
echo Some text
clean:
rm -f fmake test_second
CC=$(VAR2)
VAR2=gcc
After the make bash command the following display
rm -f fmake test_second
gcc -o fmake fmake.c foo.c
gcc -o test_second test_second.c
As said here foo.c doesn't processed because there is no dependencies for this target. But both foo.c and clean have no dependencies, but clean is processed. Why?
Because a file called foo.c exists, whereas no file called clean exists. So Make thinks that one needs to be made. Note that clean should really be declared as a phony target.

My makefile builds dependency files when not required - why?

I'm trying to create a generic makefile to build static libraries that my project uses. I've used the expertise on this site, as well as the GNU Make manual to help write the following makefile. It is working well apart from one annoying problem.
# Generic makefile to build/install a static library (zlib example)
ARCH = linux
CFLAGS = -O3 -Wall
# List of source code directories
SOURCES = src test utils
# List of header files to install
INCLUDES = src/zlib.h src/zconf.h
# Library to create
LIBNAME = libz.a
############################################################
BUILD_DIR = build/$(ARCH)
# Full path to the built library
TARGET = $(BUILD_DIR)/$(LIBNAME)
prefix = ../..
exec_prefix = prefix
libdir = $(prefix)/lib/$(ARCH)
includedir = $(prefix)/include
INSTALL_PROGRAM = install -D
INSTALL_DATA = $(INSTALL_PROGRAM) -m 644
CFILES := $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.c))
OBJECTS := $(addprefix $(BUILD_DIR)/,$(CFILES:.c=.o))
DEPENDS := $(OBJECTS:.o=.d)
.PHONY: all installdirs install uninstall clean
# Default
all: $(DEPENDS) $(TARGET)
# Build the dependency files
# (GNU Make Manual 4.14 Generating Prerequisites Automatically)
$(BUILD_DIR)/%.d: $(BUILD_DIR)
#echo "build dep for $*.c as $#"
#$(CC) -M $(CFLAGS) $*.c > $#.tmp
#sed s~.*:~"$(BUILD_DIR)/$*.o $#:"~ $#.tmp > $#
#rm $#.tmp
# Link all changed object files into static library
$(TARGET): $(OBJECTS)
$(AR) -rc $(TARGET) $?
# Compile C source to object code
$(BUILD_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
# Create the necessary directory tree for the build
$(BUILD_DIR):
#for p in $(SOURCES); do mkdir -p $(BUILD_DIR)/$$p; done
# Create the necessary directory tree for installation
installdirs:
#mkdir -p $(libdir)
#mkdir -p $(includedir)
# Install the library and headers
install: all installdirs
$(INSTALL_DATA) $(TARGET) $(libdir)
for p in $(INCLUDES); do $(INSTALL_DATA) $$p $(includedir); done
# Remove the library and headers
uninstall:
rm -f $(libdir)/$(LIBNAME)
for p in $(notdir $(INCLUDES)); do rm -f $(includedir)/$$p; done
# Remove all build files
clean:
rm -fr $(BUILD_DIR)
# Pull in the dependencies if they exist
# http://scottmcpeak.com/autodepend/autodepend.html
-include $(DEPENDS)
The problem is that the dependency files are built when they don't need to be. e.g. make install shown below rebuilds the .d files before installing.
$make --version
GNU Make 3.81
$make
build dep for utils/utils.c as build/linux/utils/utils.d
build dep for test/test.c as build/linux/test/test.d
build dep for src/zutil.c as build/linux/src/zutil.d
...
{ continues on making the other .d files, then the .o files }
...
cc -O3 -Wall -c src/zutil.c -o build/linux/src/zutil.o
cc -O3 -Wall -c test/test.c -o build/linux/test/test.o
cc -O3 -Wall -c utils/utils.c -o build/linux/utils/utils.o
ar rc { ... .o files ... }
All good up to this point! But a 'make install' now will rebuild the .d files
$make install
build dep for utils/utils.c as build/linux/utils/utils.d
build dep for test/test.c as build/linux/test/test.d
build dep for src/zutil.c as build/linux/src/zutil.d
{ ... }
install -D -m 644 build/linux/libz.a ../../lib/linux
for p in src/zlib.h src/zconf.h; do install -D -m 644 $p ../../include; done
I tried to 'touch' the .d files when the objects are built, so the update time is newer than the .o files, but that had no effect. What's wrong with my makefile?
The problem is that you include the dependency files (whatever.d), and you also have a rule for building these files. So every time you use this makefile, no matter what target you specify, it will rebuild them, include them, and execute again.
Try this for an approach to dependency handling that solves this problem. Basically, you don't need a separate rule for foo.d, just make it a side effect of the foo.o rule (it takes some thought to realize that this will work).

Resources