I believe I have a problem with the cpp preprocessor used by my Makefile (which compiles Fortran code). I have recently changed operating systems, and now compilation does not work, and I do not know enough about Makefiles or preprocessors to fix it (the Makefile was given to me many years ago).
I have recently updated from Fedora 10 to Fedora 19 (yes, should've done so earlier). After copying my code to the new system, and running gmake, I found out I was having problems with compilation. From what I have understood, what is supposed to happen is that my .F files are preprocessed and written as .f files. Apparently, the cpp preprocessor is now adding some sort of GNU disclaimer ("/* Copyright (C) 1991-2012 Free Software Foundation, Inc. This file is part of the GNU C Library.... "), which the compiler (f77) does not like. In principle, I could erase this text from each of the generated .f files, but seriously, this takes too much time.
I really don't know what is the cause of the problem. I'd like to tell cpp not output this text, or f77 to ignore it, but haven't found any flag that manages this. Considered re-writing the Makefile (using more modern compilers, for instance), but I'm a bit hopeless on this at the moment. Hopefully someone can help me with this. I'm copying the Makefile below, as well as the output.
Thanks in advance.
Makefile
# Make sure the SHELL is right
SHELL = /bin/sh
MAKE = gmake
# Define several root directories
LEP_ROOT := /home/stilgar/SUSY/NeutrinoModel2
CERN_ROOT := /usr/lib64/cernlib/2006
INCLUDES := $(LEP_ROOT)/include
INCLUDES := $(strip $(INCLUDES))
incpath := $(subst $(space),:,$(INCLUDES))
vpath %.inc $(incpath)
# Define tree
BIN_DIR := $(LEP_ROOT)/bin
# Define source directory
SRCDIR := $(LEP_ROOT)/src
# Libraries
libs := $(CERN_ROOT)/lib
libs := $(addprefix -L, $(libs))
libs += `cernlib packlib,mathlib,packlib,kernlib`
#Source files
#Main Program
src_files += $(wildcard $(SRCDIR)/main_lfv.F)
#SM Parameters
src_files += $(wildcard $(SRCDIR)/param_basic.F)
src_files += $(wildcard $(SRCDIR)/numajmass.F)
#SUSY Spectrum
src_files += $(wildcard $(SRCDIR)/texture2.F)
src_files += $(wildcard $(SRCDIR)/minserts.F)
#SUSY Flavour
src_files += $(wildcard $(SRCDIR)/gmin2.F)
src_files += $(wildcard $(SRCDIR)/lfv.F)
#Bounds
src_files += $(wildcard $(SRCDIR)/experiment.F)
src_files += $(wildcard $(SRCDIR)/directsearch.F)
#Loop Functions
src_files += $(wildcard $(SRCDIR)/fedm.F)
src_files += $(wildcard $(SRCDIR)/gedm.F)
#Mathematical Tools
src_files += $(wildcard $(SRCDIR)/biunitary3.F)
main_obj_files += $(src_files:%.F=%.o)
main_ofiles += $(notdir $(main_obj_files))
main_files += $(src_files:%.F=%.f)
depend += $(main_obj_files:.o=.d)
# Name of the executable to be created
exectry := $(BIN_DIR)/RunStuff
# Define flags
FC = f77
#FC = gfortran
#FC = g95
FFLAGS += -c
FFLAGS += $(addprefix -I, $(INCLUDES))
# Define cpp options
CPP = cpp
CPPFLAGS += -C -P -E
CPPFLAGS += $(addprefix -I, $(INCLUDES))
.PHONY : all clean cleanall help
.PHONY : sclean
all: $(exectry)
$(exectry): $(main_obj_files) $(main_files)
#echo '==================================================='
#echo ' Building executable ' $(exectry)
#echo ' '
#-rm -f $#
$(FC) -o $# $(main_obj_files) $(LFLAGS) $(libs)
#echo ' Done '
#echo '==================================================='
clean : sclean
#echo
#echo Cleaning up *.o *~ core
#echo
#-rm -f *.o core
#echo done.
sclean :
#find . -name "*.bak" -exec rm -f '{}' ';'
#find . -name "*~" -exec rm -f '{}' ';'
#find . -name "#*#" -exec rm -f '{}' ';'
cleanall :
#echo '**********************************************************'
#echo ' Clean all : '
#find . -name "*.bak" -exec rm -f '{}' ';'
#find . -name "*~" -exec rm -f '{}' ';'
#find . -name "*.log" -exec rm -f '{}' ';'
#find . -name "*.out" -exec rm -f '{}' ';'
#find . -name "core" -exec rm -f '{}' ';'
#find . -name "#*#" -exec rm -f '{}' ';'
#-rm -f *.o *.d
#echo done.
#echo '**********************************************************'
help:
#echo
#echo ' The possible options are :'
#echo ' ======================== '
#echo
#echo ' gmake -- build batch executable'
#echo ' gmake sclean -- simple clean up '
#echo ' gmake clean -- clean up a bit more '
#echo ' gmake cleanall -- clean everything'
#echo
%.f:%.F
#echo Preprocessing ... $<
#$(CPP) $(CPPFLAGS) $< > $#
%.o:%.f
#echo Compiling ... $<
#$(FC) $(FFLAGS) -o $# $<
%.d:%.F
#touch $#
#echo Updating ... $#
#makedepend -- $(CPPFLAGS) -- $< -f $#
#-rm $#.bak
Output
Preprocessing ... /home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.F
Compiling ... /home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f
/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f:2:
This file is part of the GNU C Library.
^
Non-numeric character at (^) in label field [info -f g77 M LEX]
/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f:4:
The GNU C Library is free software; you can redistribute it and/or
^
Non-numeric character at (^) in label field [info -f g77 M LEX]
/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f:5:
modify it under the terms of the GNU Lesser General Public
^
Non-numeric character at (^) in label field [info -f g77 M LEX]
(...)
gmake: *** [/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.o] Error 1
I think the problem is the -C option in the CPPFLAGS variable. The man page for cpp says that this causes the preprocessor to not discard comments. I don't think you want that. Remove that flag.
Another nit: you never want to set the MAKE variable in your makefile.
Related
I have this command from my bash script
find . -type f -name "*.c" -execdir bash -c "f={}; kos-cc $KOS_CFLAGS -c {} -o $PWD/\${f%.c}.o" \;
Its job it to recursively search the current directory ($PWD) for .c files, compile them with my "kos-cc" compiler then output all the .o files into the current working directory.
I want to move parts of my bash script into a makefile and this line is the last one that stumps me. I know how to make rules that compiles c files from directory A and outputs the .o files into directory B, but here directory A isn't always the same (Since I need to handle sub directories too). How do I do the equivalent task in a Makefile either with a rule or a command?
It is not trivial because you have your sources in different directories and simple make pattern rules cannot easily handle this. But using slightly more advanced make features can make it:
SRC := $(shell find . -type f -name "*.c")
OBJ := $(patsubst %.c,%.o,$(notdir $(SRC)))
.PHONY: all
all: $(OBJ)
define COMPILE_rule
$$(patsubst %.c,%.o,$$(notdir $(1))): $(1)
kos-cc $$(KOS_CFLAGS) -c -o $$# $$<
endef
$(foreach s,$(SRC),$(eval $(call COMPILE_rule,$(s))))
.PHONY: clean
clean:
rm -f $(OBJ)
Beware: you could have several source files with the same base name in different directories. And if this happens, you will end up with a fatal conflict of object file names...
EDIT (add conflicts detection):
The following detects conflicts situations and issues an error (replace error by warning or info depending on the severity level you assign to these conflicts):
SRC := $(shell find . -type f -name "*.c")
OBJ := $(patsubst %.c,%.o,$(notdir $(SRC)))
ifneq ($(words $(OBJ)),$(words $(sort $(OBJ))))
$(error object file name conflicts detected)
endif
(sort sorts and also removes duplicates and words returns the number of space-separated words in its string parameter).
I have two targets like this
$(OBJ1): $(BUILDDIR)/%.o: $(BUILDROOT)/proto/a/%.pb.cc
$(OBJ2): $(BUILDDIR)/%.o: $(BUILDROOT)/proto/a/b/%.pb.cc
Is it possible to combine these two into the same target somehow?
It is possible but you will need advanced make features (macros):
SRC := $(shell find $(BUILDROOT)/proto -type f -name '*.cc')
OBJ := $(addprefix $(BUILDDIR)/,$(patsubst %.cc,%.o,$(notdir $(SRC))))
compile: $(OBJ)
# $(1) is the cc source file
define MY_rule
$$(BUILDDIR)/$$(patsubst %.cc,%.o,$$(notdir $(1))): $(1)
$$(CXX) -c $$(CXXFLAGS) -o $$# $$<
endef
$(foreach f,$(SRC),$(eval $(call MY_rule,$(f))))
Demo:
$ ls -R proto
proto:
dira
proto/dira:
a.cc dirb
proto/dira/dirb:
b.cc
$ make BUILDROOT=. BUILDDIR=build compile
g++ -c -o build/a.o proto/dira/a.cc
g++ -c -o build/b.o proto/dira/dirb/b.cc
Please have a look at the section about the eval function of the GNU make manual for a complete explanation.
Late update: one comment about your other (now deleted) similar question suggested to use the vpath directive. It is tricky too and adds an important constraint which is that all source files must have different basenames. For completeness, and assuming the constraint is satisfied, here is another vpath-based solution:
vpath <pattern> dira dirb dirc:...
tells make that when searching for a file that matches <pattern>, it must explore the listed directories. So, let us:
Compute the basenames of all source files and the corresponding object files:
SRC := $(notdir $(shell find $(BUILDROOT)/proto -type f -name '*.cc'))
OBJ := $(addprefix $(BUILDDIR)/,$(patsubst %.cc,%.o,$(SRC)))
Get the list of all directories in $(BUILDROOT)/proto:
DIR := $(shell find $(BUILDROOT)/proto -type d)
Now, we are ready to use the vpath directive:
vpath %.cc $(DIR)
That's it. All in all, the following should work:
SRC := $(notdir $(shell find $(BUILDROOT)/proto -type f -name '*.cc'))
DIR := $(shell find $(BUILDROOT)/proto -type d)
OBJ := $(addprefix $(BUILDDIR)/,$(patsubst %.cc,%.o,$(SRC)))
vpath %.cc $(DIR)
compile: $(OBJ)
$(BUILDDIR)/%.o: %.cc
$(CXX) -c $(CXXFLAGS) -o $# $<
I have a project with sources in the src/ directory and its subdirectories (e.g. src/foo/ and src/bar/), and the objects in the obj directory and the matching subdirectories (e.g. obj/foo/ and obj/bar/).
I use the following (smimplified) Makefile:
SOURCES=$(shell find src/ -type f -name '*.c')
OBJECTS=$(patsubst src/%.c,obj/%.o,$(SOURCES))
all: $(OBJECTS)
obj/%.o: src/%.c
gcc -c $< -o $#
The problem
The problem is that if obj/ or one of its subdirectories doesn't exist, I get the following error:
Fatal error: can't create obj/foo/f1.o: No such file or directory
How can I tell make that %.o files depend on the creation of their containing directory?
What I tried
One solution when there are no subdirectories is to use "order only prerequisites":
$(OBJECTS): | obj
obj:
mkdir $#
But that fixes the problem only with obj/, but not obj/foo and obj/bar/. I thought about using $(#D), but I don't know how to get all this together.
I have also used hidden marker files in each directory, but that's just a hack, and I have also put a mkdir -p just before the GCC command but that also feels hacky. I'd rather avoid using recursive makefiles, if that were a potential solution.
Minimal example
To create a minimal project similar to mine you can run:
mkdir /tmp/makefile-test
cd /tmp/makefile-test
mkdir src/ src/foo/ src/bar/
echo "int main() { return 0; }" > src/main.c
touch src/foo/f1.c src/bar/b1.c src/bar/b2.c
I don't know why you consider adding mkdir -p before each compiler operation to be "hacky"; that's probably what I'd do. However, you can also do it like this if you don't mind all the directories created all the time:
First, you should use := for assigning shell variables, not =. The former is far more efficient. Second, once you have a list of filenames it's easy to compute the list of directories. Try this:
SOURCES := $(shell find src/ -type f -name '*.c')
OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
# Compute the obj directories
OBJDIRS := $(sort $(dir $(OBJECTS))
# Create all the obj directories
__dummy := $(shell mkdir -p $(OBJDIRS))
If you really want to have the directory created only when the object is about to be, then you'll have to use second expansion (not tested):
SOURCES := $(shell find src/ -type f -name '*.c')
OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
# Compute the obj directories
OBJDIRS := $(sort $(dir $(OBJECTS))
.SECONDEXPANSION:
obj/%.o : src/%.c | $$(#D)
$(CC) -c $< -o $#
$(OBJDIRS):
mkdir -p $#
I'd do it this way:
SOURCES=$(shell find src -type f -name '*.c') # corrected small error
...
obj/%.o: src/%.c
if [ ! -d $(dir $#) ]; then mkdir -p $(dir $#); fi
gcc -c $< -o $#
I'm trying to get started with CuTest to do unit testing in C.
When make-ing, I get the following error:
dev:~/bistro# make
cutest/CuTest.c:10: *** missing separator. Stop.
The file cutest/CuTest.c comes directly from the library. I have done no mods to it. Here are the concerned lines:
08 - #include "CuTest.h"
09 -
10 - /*-------------------------------------------------------------------------*
11 - * CuStr
12 - *-------------------------------------------------------------------------*/
13 -
14 - char* CuStrAlloc(int size)
Here's the Makefile I'm using, for complete reference:
NAME = bistro
SOURCES_DIR = src
OBJECTS_DIR = obj
SOURCES = $(shell find $(SOURCES_DIR) -type f -name *.c) cutest/CuTest.c
OBJECTS = $(patsubst $(SOURCES_DIR)/%.c, $(OBJECTS_DIR)/%.o, $(SOURCES))
DEPS = $(OBJECTS:.o=.d)
CFLAGS = -Wall -Werror -Wextra
COMPILER = gcc -I cutest -I $(SOURCES_DIR) $(CFLAGS)
BISTRO_MAIN = $(OBJECTS_DIR)/bistro/bistro_main.o
.PHONY: test all clean fclean re
all: $(NAME)
# header dependencies
-include $(DEPS)
$(NAME): $(OBJECTS)
$(COMPILER) -o $(NAME) $(OBJECTS)
test: $(filter-out $(BISTRO_MAIN), $(OBJECTS))
$(COMPILER) -c all_tests.c -o all_tests.o
$(COMPILER) -o test $(filter-out $(BISTRO_MAIN), $(OBJECTS)) all_tests.o
rm -f all_tests.o
$(OBJECTS_DIR)/%.o: $(SOURCES_DIR)/%.c
#if [ ! -d "$(#D)" ]; then mkdir -p $(#D); fi
$(COMPILER) -MMD -c $< -o $#
clean:
rm -Rf $(OBJECTS_DIR)/*
fclean: clean
rm -f $(NAME)
re: fclean all
What could be the cause of this error message?
EDIT 1: The makefile is indented with 4-space tabs only. Could the call to the "find" command be the cause of that? Also, how come the error says the missing separator is in the .c file?
EDIT 2: The accepted answer shows the error. In addition, the call did not work because it was searching for *.c, which should be "*.c".
It means you are using (four) spaces instead of tab symbol.
Make target's command must be indented with a tab.
See http://www.gnu.org/software/make/manual/make.html#Rule-Introduction:
Please note: you need to put a tab character at the beginning of every recipe line! This is an obscurity that catches the unwary. If you prefer to prefix your recipes with a character other than tab, you can set the .RECIPEPREFIX variable to an alternate character
Your error comes because you include a C source file into Makefile.
SOURCES = $(shell find $(SOURCES_DIR) -type f -name *.c) cutest/CuTest.c
OBJECTS = $(patsubst $(SOURCES_DIR)/%.c, $(OBJECTS_DIR)/%.o, $(SOURCES)) # cutest/CuTest.c stays cutest/CuTest.c
DEPS = $(OBJECTS:.o=.d)
-include $(DEPS) # oops, includes cutest/CuTest.c
I would like make to copy files from the source directory into a target directory. And i would like to avoid copying unchanged files. Therefore, I am trying to utilize make function of checking for newer files with a %.:%. rule.
Now, in this instance, the source and target EXTENSION are the same. There are object files elsewhere but not for the graphical assets.
I use make to copy images.
TARGET := target
SOURCE := source
GRAPHICS := $(foreach dir,$(SOURCE), $(wildcard $(dir)/*.jpg ) $(wildcard $(dir)/**/*.jpg ) $(wildcard $(dir)/*.png ) $(wildcard $(dir)/**/*.png ) $(wildcard $(dir)/*.gif ) $(wildcard $(dir)/**/*.gif ) )
JPG = $(GRAPHICS:.jpg=.tmp)
PNG = $(GRAPHICS:.png=.tmp)
GIF = $(GRAPHICS:.gif=.tmp)
And then use the following rule to copy files into target directory:
%.tmp:%.jpg
find $< | cpio -p -d -v $(TARGET)
Questions
Is it possible to string replace the TARGET directory here
and thereby use the make newer capability?
I tried
JPG = $(GRAPHICS:$(TARGET).jpg=.tmp)
But that fails with No rule to make target. Is it only possible to compare source and object in the same directory?
Can one make a rule such that the source and object are the same extension?
%.jpg:%.jpg
The closest I can come up with is:
$(TARGET)%.jpg:%.jpg
but that never runs. Even after a clean.
Here is the solution.
This 'setup' remains the same.
TARGET := target
SOURCE := source GRAPHICS := $(foreach dir,$(SOURCE), $(wildcard $(dir)/*.jpg )
$(wildcard $(dir)/**/*.jpg ) $(wildcard $(dir)/*.png ) $(wildcard $(dir)/**/*.png )
$(wildcard $(dir)/*.gif ) $(wildcard $(dir)/**/*.gif ) )
Now add a prefix to ALL (space separated) values in the $GRAPHICS string
TARGET_GRAPHICS := $(addprefix $(TARGET)/, $(GRAPHICS) )
Note that patsubst aka -- TARGET_GRAPHICS := $(patsubst %, $(TARGET)/%, $(GRAPHICS) ) -- only worked for the first entry. Perhaps I was doing it incorrectly.
Provide a pattern match for each file type. Here do whatever you wish. In my case, copy the input into the target directory. cpio will make the needed directories. cp -p might also work as needed.
$(TARGET)/%.jpg : %.jpg
#echo "--- .jpg copying " $< " to " $# " into dir " $(<D)
#find $< | cpio -p -d -v $(TARGET)
$(TARGET)/%.png : %.png
#echo "--- .png copying " $< " to " $#
#find $< | cpio -p -d -v $(TARGET)
$(TARGET)/%.gif : %.gif
#echo "--- .gif Copying " $< " to " $#
#find $< | cpio -p -d -v $(TARGET)
So you want the copy of d1/d2/f.png into out/d1/d2/f.png to make use of make's dependency checking?
out/d1/d2/f.png: d1/d2/f.png
out/d1/d2/f.png:
cp $< $#
Adding a jpg file d3/g.jpg say,
out/d3/g.jpg: d3/g.jpg
out/d1/d2/f.png: d1/d2/f.png
out/d1/d2/f.png out/d3/g.jpg:
cp $< $#
We can express this more cleanly with a static pattern rule.
out/d3/g.jpg out/d1/d2/f.png: out/% %
cp $< $#
Nice. So adding your ${GRAPHICS} and fleshing things out a bit
outdir := out/
targets := $(addprefix ${outdir},${GRAPHICS})
.PHONY: all
all: ${targets} ; : $# Success
${targets}: ${outdir}%: %
echo $< | cpio -d -p ${outdir}
Parallel safe too, so make -j9 will exercise your 8 CPUs nicely.