Circular dependency dropped: make, fortran and c building static library - c

I am trying to build a static library with mixed c and fortran code. When building the fortran files, I receive this error for each of my fortran files, but not the c files.
make: Circular file0.F90 <- file0.F90.o dependency dropped.
mpif90 -c -O2 -o "file0.F90.o" "file0.F90"
The Makefile I am using is below. My rule for F90 files is the same as for c files, so I am not sure why it should have this behaviour?
CC = mpicc
FC = mpif90
TARGET=libpxn
FCFLAGS = -O2 -fPIC
CFLAGS = -O2 -fPIC -lm -Wall
CPPFLAGS = $(CFLAGS)
SRCS = $(wildcard *.F90) $(wildcard *.c)
OBJS = $(patsubst %, %.o, $(SRCS))
# Rules
all: static
static: $(OBJS)
ar rcs $(TARGET).a $(OBJS)
%.c.o: %.c
$(CC) -c $(CFLAGS) -o "$#" "$<"
%.F90.o: %.F90
$(FC) -c $(FCFLAGS) -o "$#" "$<"
clean:
#printf "Cleaning: \n"
#find . -type f -name '*.o' -print0 | xargs -0 -I % sh -c 'printf "% "; rm -f %'
rm -f $(TARGET).so $(TARGET).a
I tried also with gnu compilers with the same result. Any ideas why this is happening?

.c is a built-in suffix, meaning at the very least there is one built-in rule defined as %.c: which will stop make from applying match anything rules (%:) to files ending with .c.
Make has no idea about .F90 on the other hand, so when it reaches the prerequisites of your %.F90.o rule, it will try to apply the match anything rule %: %.o which results in file0.F90: file0.F90.o, and a circular dependency.
The quick and dirty solution is to simply add an empty pattern rule for .F90
%.F90:
The "correct" way (IMHO) to handle this would be to rewrite your makefile to conform to the built-in implicit rules
TARGET := libpxn.a
CC := mpicc
FC := mpif90
FFLAGS := -O2 -fPIC
CFLAGS := -O2 -fPIC -Wall
ARFLAGS := rcs
CSRCS := $(wildcard *.c)
FSRCS := $(wildcard *.F90)
OBJS := $(CSRCS:.c=.o) $(FSRCS:.F90=.o)
.PHONY: all clean
all: $(TARGET)($(OBJS))
%.o: %.F90
$(COMPILE.F) $(OUPUT_OPTION) $<
%.F90:
clean:
$(info "Cleaning:")
$(RM) $(TARGET)
Make has a built-in rule for archives so you can just specify ARFLAGS and use libname(objects) as a prerequisite (IIRC if you're using GNU ar you don't need s as it'll always make an index).
The F90 recipe is copied from make's built-in rule for .F, in fact if you use .F as a fortran suffix instead of .F90 you won't even need this rule.
If you have two source files with the same stem (say foo.c and foo.F90) you'll either have to split the sources into two subdirectories (recommended), or go back to your original plan of the double suffix (you'll need to provide both rules again in that case).
I've rewritten clean as the objects are intermediate files now and will be deleted automatically after they are added to the archive.

Related

makefile: build .o files in another directory

Edit: This is the final Makefile, it build all .o files in build dir and produce one executable.
CXX = g++
CXXFLAGS = -g -Wall
SRC_DIR = ./src
BUILD_DIR = ./build
SRC = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(SRC:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
LIBS = -lusb-1.0 -lpulse-simple -lpulse
EXEC = AndroidMicLinux
all: $(EXEC)
$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -o $# -c $<
$(EXEC) : $(OBJS)
$(CXX) -o $(EXEC) $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(EXEC)
There are many issues with this makefile. Most of them have to do with expansion of variables. If you simply visualize the expansion of variables you'll likely see the problems. Remember that make is just doing text substitution to expand variables. There's no "magic" happening here.
So for example:
SRC = $(wildcard $(SRC_DIR)/*.cpp)
Let's suppose that you have the files ./src/foo.cpp and ./src/bar.cpp. That means that $(SRC) will expand to those two files. Fine. Then you have:
OBJS = $(BUILD_DIR)/$(notdir $(SRC:.cpp=.o))
How does this work? First we expand BUILD_DIR:
OBJS = ./build/$(notdir $(SRC:.cpp=.o))
Then we expand $(SRC:.cpp=.o) which gives ./src/foo.o ./src/bar.o. Then the notdir is applied which gives foo.o bar.o. That's substituted for the function, so the result is:
OBJS = ./build/foo.o bar.o
You can see this is wrong. You can't just stick a string before a function and expect that string to be appended to every word of the function! You need to explicitly tell make that you want to do that. Probably you want something like this instead:
OBJS = $(SRCS:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
Next this rule:
%.o : %.c
$(CC) -o $(OBJS) -c $(SRC)
First the recipe is wrong. What does this expand to?
g++ -o ./build/foo.o ./build/bar.o -c ./src/foo.cpp ./src/bar.cpp
Clearly that's a totally invalid compile line. You want just the one object file and source file not all of them. This is what automatic variables are for:
%.o : %.c
$(CC) -o $# -c $<
However this is still wrong: this pattern rule will never match. Why? Because when make tries to build ./build/foo.o the % pattern matches the string ./build/foo. So when make looks to see if the prerequisite %.c exists it will check for ./build/foo.c. First, your filenames end in .cpp not .c so this should be %.cpp. But beyond that, the source files are in a different directory than the destination files so you can't just use %. You have to write it like this:
$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
$(CC) -o $# -c $<
I'll also point out that convention uses CC for the C compiler; if you're compiling C++ you should be using the CXX variable. Also you set a FLAGS variable but your compile rule doesn't actually use it; you can't just put it in the link rule. And, for C++ compiler flags the convention is to use CXXFLAGS as the variable.

Makefile Stops Building Files After First .o In Out-of-Source Build

I have a bit of a huge Makefile that basically works as I want it to.
Issue: The problem I'm having is that the makefile only checks if the first .o needs updating and not if any others do. I'm not sure what part of my makefile is in error.
Context: I have project structure like this:
quendor
src
main.c
options.c
quendor.h
Makefile
When my Makefile builds, it constructs a build directory and things look as follows:
quendor
build
src
main.d
main.o
options.d
options.o
src
main.c
options.c
quendor.h
Makefile
To See the Problem: Now let's say I don't change my main.c but I do change my options.c file. In that case, when I run make again I get this:
make: 'build/./src/main.o' is up to date.
I'm not sure if this is because it's building into a build/src directory rather than just build as I intended.
Here is the full Makefile and I'm including all of it just because I'm not sure what might be a problem and I don't want to make unwarranted assumptions.
.PHONY : all clean
NAME := quendor
PLATFORM := windows
CC := gcc
LINK := gcc
BUILD_DIR ?= ./build
SRC_DIR ?= ./src
ifeq ($(PLATFORM), windows)
TARGET ?= quendor.exe
else
TARGET ?= quendor
endif
ifeq ($(CC), gcc)
CFLAGS += -std=c11 -Wall -Wextra -Wpedantic -Wconversion -Wmissing-prototypes -Wshadow -MMD -MP
LDFLAGS +=
OPT +=
endif
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:%.o=%.d)
MKDIR_P ?= #mkdir -p $(dir $#)
-include $(DEPS)
all : $(TARGET)
#echo "Building $(TARGET)"
$(TARGET) : $(OBJS)
$(LINK) $(OPT) -o $# $^ $(LDFLAGS)
$(BUILD_DIR)/%.o : %.c
$(MKDIR_P)
$(CC) $(CFLAGS) -c $< -o $#
clean:
$(RM) $(TARGET) -r $(BUILD_DIR)
This may be an artifact of how StackOverflow is parsing my Makfile but I do notice that it's showing different syntax highlighting after this line:
SRCS := $(wildcard $(SRC_DIR)/*.c)
The problem is that you are including the dependencies before you define the all rule:
-include $(DEPS)
all : $(TARGET)
If you don't specify a particular target to build on the command line (e.g., if you don't run make all) then make chooses the first explicit target in the makefile (and any included makefiles!!) as the target to build.
I assume that the dependency definitions in the $(DEPS) variable define main.o as a target and since that comes before all, it's the only thing that's run by default.
Move the -include statement later in the makefile (I typically put these all at the end of the makefile) and it will work.

makefile with gcc returns fatal error: no input files

I am trying to create a makefile for a new project. the project contains so far just some basic main func and some funcs declarations.
my makefile makes objects from source files, but no executable is compiled. exit with error:
mkdir -p build/./src/app/
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -c src/app/main.c -o build/./src/app/main.o
mkdir -p build/./src/app/
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -c src/app/Emsg.c -o build/./src/app/Emsg.o
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -o bin/Main
gcc: fatal error: no input files
compilation terminated.
Makefile:59: recipe for target 'all' failed
make: *** [all] Error 1
this is my make file:
CFLAGS := -std=gnu99 -Wall
ifeq ($(STRIP), yes)
CFLAGS := $(CFLAGS) -s
endif
BUILD_DIR := ./build
BIN_DIR := ./bin
SRC_DIRS := ./
SRC_APPS := ./src
SRC_TESTS := ./test
SRCS_APPS := $(shell find $(SRC_APPS) -name '*.c')
SRCS_TESTS := $(shell find $(SRC_TESTS) -name '*.c')
OBJS_APPS := $(SRCS_APPS:%.c=$(BUILD_DIR)/%.o)
OBJS_TESTS := $(SRCS_TESTS:%.c=$(BUILD_DIR)/%.o)
OBJS_ALL := $(OBJS_APPS)
OBJS_ALL_TESTS := $(OBJS_ALL) $(OBJS_TESTS)
INC_APPS_DIRS := $(shell find ./src -type d)
INC_INCLUDES := src/include
INC_TESTS_DIRS := test/
INC_APPS_FLAGS := $(addprefix -I,$(INC_APPS_DIRS))
INCLUDE_ALL := $(INC_APPS_FLAGS)
CC := gcc
ifeq ($(TEST), yes)
CFLAGS := $(CFLAGS) -D TEST
OBJECTS := $(OBJS_APPS) $(OBJS_TESTS)
INCLUDE := $(INC_TESTS_LIBS_FLAGS) $(INC_TESTS_FLAGS)
DEPEND_LST := apps tests
COMP_ARGS := $(CC) $(CFLAGS) $(INCLUDE) $(OBJECTS) -L$(INC_TEST_LIBS) -o bin/Test
else
DEPEND_LST := apps
COMP_ARGS := $(CC) $(CFLAGS) $(INCLUDE_ALL) $(OBJECTS) -o bin/Main
endif
# All
all: $(DEPEND_LST)
$(COMP_ARGS)
#Tests
tests: $(OBJS_TESTS)
$(BUILD_DIR)/%.o: %.c
$(MKDIR_P) $(dir $#)
$(CC) $(CFLAGS) $(INCLUDE_ALL) -c $< -o $#
# Apps
apps: $(OBJS_APPS)
$(BUILD_DIR)/%.o: %.c
$(MKDIR_P) $(dir $#)
$(CC) $(CFLAGS) $(INCLUDE_ALL) -c $< -o $#
# Clean
clean:
$(RM) -r $(BUILD_DIR)
# not sure what these two lines do..
-include $(DEPS)
MKDIR_P ?= mkdir -p
I'm simply running make.
files hierarchy is:
src dir
app dir (contains main.c and more files)
include dir (contains some .h files)
lib dir (empty)
test dir (contains another main.c file)
Makefile file
Install GNU remake and run remake -X.
It will put you into a debugger and then you can run step to see step by step what the makefile is doing. Here is that applied to your Makefile:
$ remake -X
Reading makefiles...
Updating makefiles...
Updating goal targets...
-> (/tmp/so/Makefile:45)
all: apps
remake<0> step
File 'all' does not exist.
File 'apps' does not exist.
Must remake target 'apps'.
Successfully remade target file 'apps'.
<- (/tmp/so/Makefile:56)
apps
remake<1> where
=>#0 apps at Makefile:56
#1 all at Makefile:45
remake<3> x OBJS_APPS
Makefile:17 (origin: makefile) OBJS_APPS := ...
See the link for videos. Or https://github.com/rocky/remake for some screen shots
Make's output presents the commands it runs. For a serial build, at least, this unambiguously communicates what command produced each diagnostic message emitted. In your case, the command that caused the error immediately preceeds it in the output:
gcc -std=gnu99 -Wall -I./src -I./src/app -I./src/include -I./src/lib -o bin/Main
So what's wrong with that? Why, exactly what the diagnostic says: it doesn't specify any input files to operate upon. No C source files to compile, no object files or libraries to link. Nothing from which to build the designated output file.
Supposing that you've presented a complete makefile that produces the problem for you, that command must come from an attempt to build target all via this rule:
all: $(DEPEND_LST)
$(COMP_ARGS)
That's a bit suspicious on its face, because an all target typically provides only a prerequisite list, not a recipe. Each prerequisite that may need to be built would then have its own rule. But it's not inherently wrong to provide a recipe, and we need to consider the recipe itself to determine the nature of your problem. In this case, we have suspicious point #2: the recipe is specified entirely via a single variable. But I already knew that, because I had to trace through that to identify this rule as the source of the error in the first place.
In particular, the only place where the text bin/Main appears in the makefile is in this else block:
else
DEPEND_LST := apps
COMP_ARGS := $(CC) $(CFLAGS) $(INCLUDE_ALL) $(OBJECTS) -o bin/Main
endif
That indeed provides the command line variable referenced by the all target (and by nothing else), and it matches up cleanly with the command that causes the error. And what do we find when we match the bits of the command line to the variables from which that version of COMP_ARGS is built? We find that all the bits are covered by variables other than OBJECTS, which evidently expands to nothing (you can even see the separate leading and trailing space characters around its empty value). And why does OBJECTS expand to an empty value? Because it is never set when that branch of the conditional is exercised.
Personally, I would be inclined to rewrite the whole makefile to be more idiomatic and to rely less on GNU make extensions, but the simplest way forward would probably be to put an appropriate definition of the OBJECTS variable in the else block I pointed out.

Makefile to convert all *.c to *.o

I am writing a Makefile for compiling all *.c files in a directory into
*.o . There are many *.c files so I don't want to do it on individual basis,
I tried
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $# $<
but this isn't working ... please help me understand what's going wrong here ...
You told make how to generate a *.o out of a corresponding *.c file. (Not that you needed to, because make already knows as much, at least as long as you don't try anything more specific than what you wrote in your rule.)
You didn't tell make you wanted any specific foo.o or bar.o, so make does nothing.
Either add a list of object files you want generated to the Makefile, or call make foo.o specifically.
----
For what it's worth, have a look at this... there are some tricks and lessons in there, which I trust your curiosity will find out about. Most importantly, it adds compiler warnings, and automated header dependency handling.
This is assuming GNU make for e.g. patsubst, the existence of find, and GCC (for the dependency handling via -MMD -MP). If you want to go cross-platform, I'd suggest a meta-build system like CMake, which I am using myself.
PROJNAME := MyProject
PROJDIRS := subdir1 subdir2
SRCFILES := $(shell find $(PROJDIRS) -type f -name "\*.c")
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))
WARNINGS := -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
-Wredundant-decls -Wnested-externs -Winline \
-Wuninitialized -Wconversion -Wstrict-prototypes
CFLAGS := -g -std=c99 $(WARNINGS)
.PHONY: all clean
all: $(PROJNAME)
clean:
-#$(RM) $(wildcard $(OBJFILES) $(DEPFILES) $(PROJNAME))
-include $(DEPFILES)
$(PROJNAME): $(OBJFILES)
#$(CC) $(LDFLAGS) $^
%.o: %.c Makefile
#$(CC) $(CFLAGS) -MMD -MP -c $< -o $#
Your rule maps a single .c file to a single .o, and mirrors an existing implicit rule.
In order to generate all the .o files corresponding to a set of .c files, you can create a list of object file names from the list of .c files, and then make a target that depends on that list:
SRC = $(wildcard *.c) # list of source files
OBJS = $(patsubst %.c, %.o, $(SRC)) # list of object files
objs : $(OBJS) # target
Then generate the object files with
make objs
This will build a .o file for each .c one.
You can add a rule OBJS, it will do it for you
OBJS = $(SRCS:.c=.o)
With you .c files in the SRCS, and if they are too many do:
SRCS = $(wildcard *.c)
Then add it when you'll run make
$(NAME) : $(OBJS)
[...]

GNU make implicit archive rule with stem

I am trying to setup a Makefile to build either static (.a) and dynamic (.so) libraries depending on the target file extension.
I previously used the following Makefile for static libraries only :
NAME := config
LIB := lib$(NAME).a
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
CFLAGS += -W -Wall
.PHONY: all clean fclean re
all: $(LIB)
clean:
#$(RM) $(OBJ)
fclean: clean
#$(RM) $(LIB)
re: fclean all
$(LIB): $(LIB)($(OBJ))
ranlib $#
My main goal is to be able to compile multiple libraries by only changing the LIB and NAMEvariables.
Everything worked fine, so I added the following for the dynamic libraries :
LDFLAGS += -shared
%.so: CFLAGS += -fPIC
%.so: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^
And changed the $(LIB): rule by the following generic rule :
%.a: %.a($(OBJ))
ranlib $#
If I change LIB to lib$(NAME).so everything works as expected, but with the .a extension, make prints me this error :
make: *** No rule to make target 'libconfig.a', needed by 'all'. Stop.
The only solution I found was to add another explicit rule like that :
%.a($(OBJ)): $(OBJ)
$(AR) rv $# $^
And now everything works.
But adding this explicit rule prevents me from relying only upon GNU make's implicit rules, and makes me call explicitly ar, which I wanted to avoid.
Is this some kind of bug or am I missing something ?
GNU Make 3.82
Built for x86_64-unknown-linux-gnu
Some quick testing seems to indicate that this can't be done. It appears that the specialized make archive support is a makefile parse time feature. That is the literal archive name must exist in the actual makefile for it to take effect.
I tried a couple of workarounds but wasn't able to get any of them to work correctly. The closest I could manage was:
$(foreach a,$(filter %.a,$(MAKECMDGOALS) $(.DEFAULT_GOAL)),$(eval $a: $a($$(OBJ)); ranlib $$#))
which doesn't work for a default goal of all but would if the default was the library name and/or if the library name is an explicit make target. You could stick any other known library names in there too and then they should work even as implicit requirements of other targets but that's a manual process.
You need to tell make which .o files a given .a file depends on. You can do that with a simple dpendency with no action:
libconfig.a: libconfig.a($(OBJ))
make will then invoke the default rule for putting .o files into a .a file to actually build libconfig.a
Archives and shared libraries don't share the same prerequisites syntax, so it is not possible to have a single rule that handle both.
The simplest solution is to use a conditional on the target extension:
ifeq "$(suffix $(LIB))" ".a"
$(LIB): $(LIB)($(OBJ))
else ifeq "$(suffix $(LIB))" ".so"
$(LIB): override CFLAGS += -fPIC
$(LIB): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
endif
A working Makefile that meets the requirements looks now like this:
NAME := config
LIB := lib$(NAME).so
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD -MP
CFLAGS := -W -Wall
LDFLAGS := -shared
ARFLAGS := rs
.PRECIOUS: $(OBJ)
.PHONY: all clean fclean re
all: $(LIB)
clean:
$(RM) $(OBJ) $(DEP)
fclean: clean
$(RM) $(LIB)
re: fclean all
ifeq "$(suffix $(LIB))" ".a"
$(LIB): $(LIB)($(OBJ))
else ifeq "$(suffix $(LIB))" ".so"
$(LIB): override CFLAGS += -fPIC
$(LIB): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
endif
ifeq "$(MAKECMDGOALS)" ""
-include $(DEP)
endif
Note that the ARFLAGS variable controls which flags are passed to the invocation of ar. Here I use the r flag to replace existing object if it exists and the s flag to build or update the index (ranlib is not necessary anymore with this).

Resources