passing target name to secondary targets - c

The makefile has multiple targets which will called for all files in the directory. The automatic variable does not get replaced for the target.
TARGETS += txyz_abc txyz_def
.PHONY: all clean
all: $(TARGETS)
txyz_abc: $(UY_DIR)/$(OBJ)/support.o \
$(UX_DIR)/$(OBJ)/%.o
$(CC) $(CFLAGS) -c $< -o $#
$(UX_DIR)/$(OBJ)/%.o: %.c
$(call mkdir, $(UX_DIR)/$(OBJ))
$(CC) $(CFLAGS) -c $< -o $#
$(UY_DIR)/$(OBJ)/support.o: $(UY_DIR)/src/support.c
$(call mkdir, $(UY_DIR)/$(OBJ))
$(CC) $(CFLAGS) -c -o $# $<
on make support.o is generated. but throws an error that no rule to make target '../ux_src/obj/%.o", needed by 'txyz_abc'.

Related

Makefile how to use logical OR between prerequisites?

My source files are organized nicely in a folder, that contains subfolders, that also contains source files.
The subfolders don't branch any further.
All object files are just meant to be created and stored in the same folder.
I don't want to manually list the name of the subdirs in the prerequisites when writing the target that generates my object files:
Right now this works:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(OBJ)/%.o: $(SRC)/$(subdir1)/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(OBJ)/%.o: $(SRC)/$(subdir2)/%.c
$(CC) -c $< -o $# $(CFLAGS)
...
But I want it to look something like this:
$(OBJ)/%.o: $(SRC)/%.c OR $(SRC)/*/%.c
$(CC) -c $< -o $# $(CFLAGS)
I understand that the title most likely isn't the real question to be asked, but I'm looking for any solution. Also, I know that the * doesn't work as a placeholder here.
First, you can simplify the makefile you have by using vpath:
$(OBJ)/%.o: %.c
$(CC) -c $< -o $# $(CFLAGS)
vpath %.c $(SRC) $(SRC)/$(subdir1) $(SRC)/$(subdir2)
Then, if you really don't want to specify the subdirectories:
vpath %.c $(shell find $(SRC) -type d)

Gnu make exclusive OR (kinda) in prerequistires list?

I have a pattern rule like this:
$(BIN_DIR)/%: $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Is it possible to do something like:
$(BIN_DIR)/%: $(SOURCES_DIR)/%.c OR $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Where OR means if there the target $(BIN_DIR)/progname requsted, first look for $(SOURCEDS_DIR)/progname.c and it will be the only prerequisite. If there is no such file, prerequisites list will be $(SOURCES_DIR)/progname/*.c as it is now in the original rule? Maybe some other way to achieve this behaviour?
Full Makefile (tests ommited as irrelevant):
SOURCES_DIR = src
INCLUDE_DIR = $(SOURCES_DIR)/include
OBJECTS_DIR = build
BIN_DIR = bin
LIB_DIR = lib
INCLUDE_FLAGS = -I$(INCLUDE_DIR)
CFLAGS=-g --std=c99 -Wall -Wextra -O2 $(INCLUDE_FLAGS)
LDLIBS=-ldl -lm $(OPTLIBS)
LIB_SOURCES=$(wildcard $(SOURCES_DIR)/lib*)
BIN_SOURCES=$(filter-out $(INCLUDE_DIR) $(LIB_SOURCES),\
$(patsubst %.c,%,$(wildcard $(SOURCES_DIR)/*)))
BINS=$(addprefix $(BIN_DIR)/, $(notdir $(BIN_SOURCES)))
OBJECTS=$(patsubst %.c,%.o,\
$(subst $(SOURCES_DIR),$(OBJECTS_DIR),\
$(wildcard $(SOURCES_DIR)/lib**/*.c)))
LIBS=$(addsuffix .a, $(addprefix $(LIB_DIR)/, $(notdir $(LIB_SOURCES))))
SO_LIBS=$(patsubst %.a,%.so,$(LIBS))
all: $(OBJECTS) $(LIBS) $(SO_LIBS) $(BINS)
$(OBJECTS_DIR)/%.o: CFLAGS+= -fPIC
$(OBJECTS_DIR)/%.o: $(SOURCES_DIR)/%*
#mkdir -p $(#D)
$(CC) $(CFLAGS) -c $(SOURCES_DIR)/$*.c -o $# $(LDFLAGS) $(LDLIBS)
$(LIB_DIR)/%.a: $(OBJECTS)
$(AR) rcs $# $(OBJECTS_DIR)/$*/*.o
ranlib $#
$(LIB_DIR)/%.so: $(LIBS)
$(CC) -shared $(OBJECTS_DIR)/$*/*.o -o $# $(LDFLAGS) $(LDLIBS)
# the rule i'm talking about
$(BIN_DIR)/%: $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Confession: tl;dr
Is it possible to do something like:
$(BIN_DIR)/%: $(SOURCES_DIR)/%.c OR $(SOURCES_DIR)/%/*.c
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
You can do it by declaring the pattern rule twice.
Put the recipe in a macro to avoid writing that twice.
define recipe
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
endef
$(BIN_DIR)/%: ${SOURCES_DIR}/%.c
$(recipe)
$(BIN_DIR)/%: $(SOURCES_DIR)/%/*.c
$(recipe)
Ok, but don't do this.
Pattern rules are an ugly hack IMHO—I don't like the ambiguity.
Different make versions do different things.
(Wildcards aren't much better, but I won't comment further here.)
It always feels cleaner to write explicitly what you want.
You can still use patterns,
but use static pattern rules by explicitly listing the targets that the patterns apply to.
recipe = $(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
single-source-targets := $(addprefix ${BIN_DIR}/,counter filter)# for example
multi-source-targets := $(addprefix ${BIN_DIR}/,engine database)
${single-source-targets}: ${BIN_DIR}/%: ${SOURCES_DIR}/%.c ; $(recipe)
${multi-source-targets}: ${BIN_DIR}/%: ${SOURCES_DIR}/%/*.c ; $(recipe)
Its impossible to give a specific answer without the entire Makefile.
But since this is a question of two variable file paths: conditional search directories ($(SOURCES_DIR) or $(SOURCES_DIR)/progname), AND conditional files to search for ($(SOURCES_DIR)/progname.c or $(SOURCEDS_DIR)/progname/*.c), the solution is more complicated than a simple makefile rule.
The best way I can think of is to use conditionals to set the dependency directory and filename as shown below.
ifneq ("$(wildcard $(SOURCES_DIR)/progname.c)","")
DEPS = $(SOURCES_DIR)/progname.c
else
DEPS = $(SOURCES_DIR)/progname/*.c
endif
$(BIN_DIR)/%: $(DEPS)
$(CC) $? $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
Well, i got what i want, even though i don't really like how I did this, so any other variants are appritiated. It's difficult to build prerequisites list conditionally, so i decided to use different targets, and then just copy files where i wanted. This did the job, but still not very pretty. I just added following lines to the Makefile:
ONEFILERS_SOURCES=$(wildcard $(SOURCES_DIR)/*.c)
ONEFILERS=$(patsubst %.c,%,$(subst $(SOURCES_DIR),$(ONEFILERS_TMP),\
$(ONEFILERS_SOURCES)))
$(ONEFILERS_TMP)/%: $(SOURCES_DIR)/%.c $(SHARED_INCLUDES)
#mkdir -p $(#D)
$(CC) $< $(CFLAGS) $(LDFLAGS) -o $# $(LDLIBS) $(LIBS)
#install $# $(BIN_DIR)
Any better solutions are welcome.

Makefile doesn't rebuild objects on header modification

I have made a Makefile for compiling my C programm but it's not building object when i change one of the headers.
My MakeFile:
CC=gcc
CFLAGS=-O3 -Wall
LDFLAGS=-I/usr/include/mysql -L/usr/lib/x86_64-linux-gnu -lmysqlclient
SOURCES=$(wildcard *.c)
OBJECTS=$(SOURCES:.c=.o)
EXECUTABLE=bin/beta_parser
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) -o $# $^ $(CFLAGS) $(LDFLAGS)
%.o:%.c types.h cstes.h headers.h mysql.h
$(CC) -o $# -c $< $(CFLAGS)
.PHONY: clean mrproper
clean:
rm -rf *.o
mrproper:
rm -rf $(EXEC)
What have I done wrong ?
EDIT : Corection of the Makeil after a great comment.
Although there are other more elegant tricks, in your case, I think something like
$(OBJECTS): types.h cstes.h headers.h mysql.h
%.o: %.c
$(CC) -o $# -c $< $(CFLAGS)
should be sufficient.
Scanning your sources for dependencies is outside the scope of Make (although there are other tools, such as CMake which will do this automatically). You need to add an explicit rule to generate these dependencies, but this can be done in many different ways. I've sometimes used the following technique:
OBJECTS = ....
-include $(OBJECTS:.o=.d)
...
$(OBJECTS): %.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(CC) $(CFLAGS) $(DEPFLAGS) $< > $*.d
Google for "make automatic dependency generation" will show you other ways to do it as well.

makefile compiles object file with no rule

My makefile is compiling write_time.o although i'm not giving it any rule. However, when I actually write a rule for it, it wouldn't compile. Any suggestion on what might cause this problem? Below is my makefile:
INCLUDES = -I../include -I/opt/local/include
CC = gcc
OBJS = image_io.o xcorr.o textfile_io.o main.o array_processing.o \
fit2d.o poly.o mattran.o matsolve.o nelder_mead.o process.o \
open_seq_file.o write_time.o close_seq_file.o
DEBUGS = -g
CFLAGS = $(INCLUDES) -Wall -O2 $(DEBUGS)
DESTDIR = ../bin
LDFLAGS = -L. -L/opt/local/lib -ltiff -lm -L../lib -lmatrix ../include/seq_io.h
DEPS = ../include/file_io.h ../include/corr.h \
../include/matrix.h /opt/local/include/tiffio.h \
/opt/local/include/tiff.h ../include/seq_io.h
#../include/nmsimplex.h
all: $(DESTDIR)/main
image_io.o: image_io.c ../include/file_io.h /opt/local/include/tiffio.h \
/opt/local/include/tiff.h
$(CC) $(CFLAGS) -o $# -c $<
xcorr.o: xcorr.c ../include/file_io.h
$(CC) $(CFLAGS) -o $# -c $<
textfile_io.o: textfile_io.c ../include/file_io.h
$(CC) $(CFLAGS) -o $# -c $<
array_processing.o: array_processing.c ../include/file_io.h
$(CC) $(CFLAGS) -o $# -c $<
fit2d.o: fit2d.c ../include/matrix.h
$(CC) $(CFLAGS) -o $# -c $<
poly.o: poly.c ../include/corr.h
$(CC) $(CFLAGS) -o $# -c $<
nelder_mead.o: nelder_mead.c ../include/corr.h
$(CC) $(CFLAGS) -o $# -c $<
# nmsimplex.o: nmsimplex.c ../include/nmsimplex.h
# $(CC) $(CFLAGS) -o $# -c $<
process.o: process.c ../include/corr.h
$(CC) $(CFLAGS) -o $# -c $<
mattran.o: mattran.c ../include/matrix.h
$(CC) $(CFLAGS) -o $# -c $<
matsolve.o: matsolve.c ../include/matrix.h
$(CC) $(CFLAGS) -o $# -c $<
open_seq_file.o: open_seq_file.c ../include/seq_io.h
$(CC) $(CFLAGS) -o $# -c $<
close_seq_file.o: close_seq_file.c ../include/seq_io.h
$(CC) $(CFLAGS) -o $# -c $<
main.o: main.c ../include/file_io.h ../include/nmsimplex.h ../include/corr.h ../include/seq_io.h
$(CC) $(CFLAGS) -o $# -fopenmp -c $<
$(DESTDIR)/main: $(OBJS)
$(CC) -o $# -fopenmp $^ $(LDFLAGS)
.PHONY: clean
clean:
rm -f *.o *~
This compiles fine. But when I add in:
write_time.o: write_time.c ../include/seq_io.h
$(CC) $(CFLAGS) -o $# -c $<
I get the error:
make: *** No rule to make target `../include/seq_io.h', needed by `write_time.o'. Stop.
That error probably means that ../include/seq_io.h doesn't exist. You've listed it as a dependency, and make insists that dependencies either exist or that there is some way to automatically create them.

Using a Makefile to store object files in two different directories? [C]

I need to modify the Makefile I have to store only the object file associated with "record.c" into the bin folder. Here is what my directory structure looks like before executing Make.
bin/
include/
-hash_table.h
-history.h
-parser.h
-record.h
-shell.h
-variables.h
lib/
obj/
src/
-hash_table.c
-history.c
-parser.c
-record.c
-shutil.c
-sshell.c
-variables.c
...and here is the Makefile:
# Beginning of Makefile
SRC = src/shutil.c src/parser.c src/sshell.c src/history.c src/hash_table.c src/variables.c src/record.c
OBJS = obj/shutil.o obj/parser.o obj/sshell.o obj/history.o obj/hash_table.o obj/variables.o bin/record.o //<----
HEADER_FILES = include/shell.h include/parser.h include/history.h include/hash_table.h include/variables.h include/record.h
EXECUTABLE = sshell
LIBS = lib/libshell.so lib/libparser.so lib/libhistory.so lib/libhash_table.so lib/libvariables.so lib/librecord.so
LIBCFLAGS = $(CFLAGS) -D_REENTRANT -fPIC
CFLAGS = -Wall
CC = gcc
# End of configuration options
#What needs to be built to make all files and dependencies
all: $(EXECUTABLE)
#Create the main executable
$(EXECUTABLE): $(OBJS) $(LIBS)
$(CC) -o $(EXECUTABLE) obj/sshell.o -Llib -lparser -lshell -lhistory -lhash_table -lvariables -lrecord
#Create the library files
lib/libparser.so: obj/parser.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libshell.so: obj/shutil.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libhistory.so: obj/history.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libhash_table.so: obj/hash_table.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/libvariables.so: obj/variables.o
$(CC) $(LIBFLAGS) -shared $^ -o $#
lib/librecord.so: bin/record.o //<----
$(CC) $(LIBFLAGS) -shared $^ -o $#
#Recursively build object files
obj/%.o: src/%.c //<---- I feel like this is causing the problem.
$(CC) $(CFLAGS) -I./include/ -c $< -o $#
#Define dependencies for objects based on header files
#We are overly conservative here, parser.o should depend on parser.h only
$(OBJS) : $(HEADER_FILES)
clean:
-rm -f $(EXECUTABLE) obj/*.o lib/*.so lib/*.a bin/*.o
-rm -f .sshell_history.txt
run: $(EXECUTABLE)
(export LD_LIBRARY_PATH=lib; ./$(EXECUTABLE))
# End of Makefile
With what I have done (most likely completely off) it doesn't compile record.c and says bin/record.o does not exist. I am not really experienced with Makefiles so I am wondering if I can have some help. Thanks!
Try using the rule .c.o instead of obj/%.o: src/%.c
Edit:
If that doesn't work, maybe adding the following rule will do the job:
bin/%.o: src/%.c
$(CC) $(CFLAGS) -I./include/ -c $< -o $#

Resources