What is the best approach to use different CFLAGS for the same source files? - makefile

i need to build the same source tree twice,
1 - with normal cflags to build the project binary
2 - with cflags plus -fPIC to build a static library that would be some sort of SDK to develop project dynamic modules.
Using only one Makefile, what is the best approach to accomplish this?
It would be nice to do some sort of :
all: $(OBJECTS)
lib_rule: $(OBJECTS)
CFLAGS += -fPIC
.cpp.o:
$(CC) -c $< -o $# $(CFLAGS)
But obviously it can't be done.
Thanks

One thing I've used in the past is a different extension:
.cpp.o:
$(CC) -c $< -o $# $(CFLAGS)
.cpp.lo:
$(CC) -c $< -o $# $(CFLAGS) $(EXTRA_CFLAGS)
You then build your static library from the .lo files and you binary from the .o files:
prog: a.o b.o
libsdk.a: a.lo b.lo
Assuming you are using GNU Make, you can use some built in functions to only have to maintain the list of objects one time:
OBJS = a.o b.o
LOBJS = $(patsubst %.o, %.lo, $(OBJS))

GNU make offers also "Target-specific Variable Values". Consider the following Makefile:
# Makefile
CFLAGS := My Cflags
all: $(OBJECTS)
#echo "$# CFLAGS is: " $(CFLAGS)
lib_rule: CFLAGS += extended by -fPIC
lib_rule: $(OBJECTS)
#echo "$# CFLAGS is: " $(CFLAGS)
# Makefile - end.
$ make all
all CFLAGS is: My Cflags
$ make lib_rule
lib_rule CFLAGS is: My Cflags extended by -fPIC
$
(Please note: if you copy and paste the example, remember to re-add the tabstops in front of the command lines. I always get caught by that.)

Instead of placing the compiled .o files in the same directory as the source, I create them in labeled sub-directories. In your case, you can have the static library files created as source_dir/lib/*.o and your normal files as source_dir/bin/*.o. In your different build targets after you set up your unique CFLAGS, simply generate a DIR_NAME value holding the name of the appropriate sub-folder. You can use this variable when you create the paths for the compiler to use when building and when linking.

In a different make tool such as CMake, you can express something like that much more easily.
For instance, you could well do
set(sources ABC.cpp DEF.cpp XYZ.cpp)
ADD_LIBRARY(mylib STATIC ${sources})
add_executable(myExecutable ${sources} main.cpp)
Or, you could repeatedly build the same directory with different flags by including it several times from the directory's logical parent, i.e.
set(MyTweakFlag 2)
add_subdirectory("libDir" "libDir2")
set(MyTweakFlag 3)
add_subdirectory("libDir" "libDir3")
...and then use if() or whatnot in the child directory to set the right flags.
Particularly if you have many such configurations, using make becomes quite fragile; make won't correctly find the transitive closure of recursive make dependancies (and certainly won't correctly find the dependancy on the makefile itself - if you change flags, say) so if you're going to do complicated makefile magic: do it with a better tool!
(CMake simply happens to be what I replaced make with, but there are various other replacements possible, of course)

Related

Make uses same source file for different object files

Make chooses the same source file for different object files. Both are a list of files, only with different filenames. Make switches between the object files but not the source files.
I've already tried some of the answers on StackOverflow with related problems, though those solutions either seem too complicated for what's needed, some don't work and others need the files to be in one directory.
I've also tried compiling the files together in one go (with gcc), but this gives some problems with the linking of the rest of the file.
$(OBJFILES): $(SRCFILES)
$(CC) $(CCFLAGS) -c $< -o $#
$(OBJFILES) contains the following files:
src/kernel.o src/screen/screen_basic.o
And $(SRCFILES) contains these files:
src/kernel.c src/screen/screen_basic.c
Basically, src/kernel.c gets compiled to both src/kernel.o and src/screen/screen_basic.o, while src/screen/screen_basic.c never gets compiled.
What's run by make (I replaced the options for gcc with the variable names to keep it short):
i686-elf-gcc $(CFLAGS) $(WARNINGS) -c src/kernel.c -o src/kernel.o
i686-elf-gcc $(CFLAGS) $(WARNINGS) -c src/kernel.c -o src/screen/screen_basic.o
I don't really know what you need to see what's going wrong. So, the source files (all of them) are at https://github.com/m44rtn/vireo-kernel.
It may be nice to know that this is a rewrite of the project. In the previous 'version' I manually added the file names to the makefile, which worked perfectly, but isn't nice when you have to add new files or when you're moving them around. That makefile is on the master branch (which ISN'T the default branch anymore).
The make version is the newest:
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
So, I expected this to work absolutely great. I thought it would just compile all files in the list. Unfortunately, it didn't. I don't really know what's going wrong here.
It compiles kernel.c to both kernel.o and screen_basic.o. I, of course, had hoped it would compile kernel.c to kernel.o and screen_basic.c to screen_basic.o.
Later on, the two files get linked. However, because they are the same, the linker throws errors because everything is defined twice, which isn't ideal.
I've tried to solve it by compiling every C file in one go, but this gave some issues with linking the Assembly files with the C files (sometimes making it non GRUB multibootable, which is necessarry to have, in my case).
I do not know what's wrong with the makefile for it to behave like this.
All the solutions from stack overflow I've tried:
Some solutions involve throwing all files in the root directory and just using:
%.o: %.c
(..)
However, this project will have a lot of files. This makes having everything in the same directory very annoying, very fast. I think this didn't work as well, but I don't know if that's true or just my brain lying to me. Sorry.
I've heard something about 'static rules':
$(OBJFILES): %.o: %.c
(..)
This didn't work, however I may have used it wrong. I don't know.
I like the makefile to stay the same as much as possible, because it's a very convenient one (it just detects all files automatically).
I really hope I've provided enough information, and that this question wasn't already asked. If it has been, I'm sorry in advance.
If you need more information, please ask! :)
--EDIT--
I'm quite new to make in this way, although I've used it for five years. I've always used it wrong. It is possible that my makefile is very ugly or bad. And I did use an example to write the makefile.
Consider the rule...
$(OBJFILES): $(SRCFILES)
$(CC) $(CCFLAGS) -c $< -o $#
Let's say, for the sake of argument, that we have...
SRCFILES := a.c b.c
OBJFILES := a.o b.o
If you expand the rule manually it becomes...
a.o b.o: a.c b.c
$(CC) $(CCFLAGS) -c $< -o $#
I think (correct me if I'm wrong) you are under the impression that this will be interpreted by make as a.o depends on a.c and, separately, b.o depends on b.c. That's not the case. What it actually states is that both of a.o and b.o depend on both of a.c and b.c.
So, when make tries to update the target a.o it sees the full prerequisite list of a.c and b.c and assigns the first of these, a.c, to the builtin variable $<. That's why you always see the first source file in $(SRCFILES) being compiled.
The best way to solve this probably depends on how you intend to structure your source file hierarchy and object files but you might want to take a look at using one or more vpath directives.
The pattern rule does not put all objects in root directory, consider
CFILES := path/to/a.c b.c
OBJFILES := $(foreach f,$(CFILES),$(f:%.c=%.o))
all: $(OBJFILES)
%.o: %.c
$(CC) $(CCFLAGS) -c $< -o $#
Here is what you get:
cc -c path/to/a.c -o path/to/a.o
cc -c b.c -o b.o
The following is not a recommendation, but kind of an exercise in makefile programming.
If you have $(SRCFILES) and want to compile them one at a time, you can use:
define compile
$1.o: $1.c
$(CC) $(CCFLAGS) -c $$< -o $$#
endef
$(foreach src,$(SRCFILES),$(eval $(call compile, $(src:%.c=%))))
If the correspondence of lists of sources and objects is not by name, but only by placement in list, you can destroy the CFILES list
define compile
src := $(CFILES)
CFILES := $(wordlist 2, $(words $(CFILES)), $(CFILES))
$1: $(src)
$(CC) $(CCFLAGS) -c $$< -o $$#
endef
$(foreach obj,$(OBJFILES),$(eval $(call compile, $(obj))))
Or you may use a helper list, to keep CFILES unchanged:
helperlist := $(CFILES)
define compile
src := $(firstword $(helperlist))
helperlist := $(wordlist 2, $(words $(helperlist)), $(helperlist))
$1: $(src)
$(CC) $(CCFLAGS) -c $$< -o $$#
endef
$(foreach obj,$(OBJFILES),$(eval $(call compile, $(obj))))

How to have the proper order of .mod in makefile

I'm trying to do a Makefile for my project in Fortran and make it reusable for now projects. The Mkefile I have come up with after many tries is the following. The thing is that it works OK in few scenarios but right now I have this files:
main.f90, initial.f90, parameters.f90, functions.f90
The first one has my program and the others are modules where I have subroutines. The thing is that initial needs parameters to work but the Makefile decides to try compiling initial before parameters. Is there a way I can make it to choose them in the right order?
vpath %.o obj
vpath %.mod mod
TOP_DIR = .
MOD_DIR = $(TOP_DIR)/mod
OBJ_DIR = $(TOP_DIR)/obj
SOURCES = $(wildcard *.f90)
OBJECTS := $(patsubst %.f90, $(OBJ_DIR)/%.o, $(SOURCES))
ALL_MODULES = $(patsubst %.f90, %.mod, $(SOURCES))
MODULES = $(filter-out main.mod, $(ALL_MODULES))
FFLAGS = -O3 -J$(MOD_DIR) -march=native -fimplicit-none -Wall -Wline-truncation -fwhole-file
.PHONY: main clean
main: main.out
./main.out
main.out: $(MODULES) $(OBJECTS)
gfortran $(FFLAGS) $(OBJECTS) -o main.out
$(OBJ_DIR)/%.o : %.f90
gfortran $(FFLAGS) $^ -c $#
%.mod: %.f90
gfortran $(FFLAGS) -c $^
clean:
rm -f $(OBJ_DIR)/*.o *.out $(MOD_DIR)/*.mod
List the source files in the dependency order instead of automatically: SOURCES = parameters.f90 initial.f90 functions.f90.
Separate the source for the modules and for the program: main.f90 does not, in general, generate .mod files and that will break the simplistic Makefile you have.
I also advise to use another build system (cmake, for instance) but for small projects you can get by with a Makefile if you prefer to.
With modern Fortran compilation order is very important. When using makefiles, for anything non-trivial it's too tedious to keep track of the dependencies manually. Enter various tools to generate these dependency lists. I have successfully used makedepf90 which is available as a package in EPEL (for RHEL/CentOS) and Debian/Ubuntu.
You can even make a makefile rule for regenerating the dependency list, if you keep the list in a separate file, like:
include depend.mk
# Dependencies generated by "makedepf90" tool.
depend depend.mk:
cd $(srcdir) && makedepf90 $(yourprogramname_SOURCES) >depend.mk
The above BTW works both with plain makefiles and automake (in which case you put the above snippet to your Makefile.am)

Different dependency locations in Makefile based on target

I'm trying to set up a Makefile to handle two different targets from one set of sources, and I'm a little out of my element. The vast majority of it works fine, but my dependency structure is hosed and thus I'm forced to do a full recompile each time. A pared down sample is as follows:
first: OBJDIR = obj
second: OBJDIR = obj-2
SRCS = $(wildcard src/*.cc)
OBJECTS = $(patsubst %.cc,$(OBJDIR)/%.o,$(SRCS))
first: CFLAGS = -g -Wall -Wextra -std=c++11 -MMD
second: CFLAGS = -g -Wall -Wextra -std=c++11 -MMD -DCOMPILE_FLAG
$(OBJDIR)/%.o: %.cc
#mkdir -p $(OBJDIR)/src
clang++ -c $(CFLAGS) -o $(OBJDIR)$# $<
#DEPENDENCIES AREN'T WORKING PROPERLY
-include $(OBJECTS:.o=.d)
first: $(OBJECTS)
clang++ -o gen/first $(OBJECTS)
second: $(OBJECTS)
clang++ -o gen/second $(OBJECTS)
If I #echo $(OBJECTS:.o=.d) under my first: executable generation (or as it's used in the compilation step), it properly expands to /obj/src/filename.d. However, when it's in the include line, it shows up simply as /src/filename.d. Obviously the .d files don't exist in that location, so it doesn't find them and does a full recompile.
Makefiles are not something I'm heavily experienced with, so if there are better ways to do anything up above, I'm all ears. The key point, though, is being able to have two sets of object files and two sets of dependencies from the same sources.
--
To clarify on the eventual goals, what I have is a set of source files that are used to build two separate executables, with the differences handled via #ifdefs.
What I want to get out of the makefile structure is a single makefile with two targets. Each target generates its own .o/.d files, so that when a change is made to the source, I can run make first and make second to generate the two new executables without having to recompile everything from scratch. I've handled this previously by having two separate makefiles, but that just seems wrong.
You've missed a critical sentence in the GNU make manual related to target-specific variables:
As with automatic variables, these values are only available within the context of a target's recipe
This means that you can't use target-specific variables in either the target or prerequisite lists: any variables used there will ALWAYS have the global value and never the target-specific value. Similarly, include lines are parsed as the makefile is read in: there's no target context at all here either so the global value is used.
Further, any time you see ANY rule in a makefile that is creating a file which is not exactly $# but is instead some modification of it, that's a red flag and you know you have a problem: -o $(OBJDIR)$# is wrong.
In general, there's a lot wrong with this makefile and it's not entirely clear exactly what you're trying to do here. Maybe if you stepped back and described the goal you want to achieve we can give you some pointers.
I believe the answer is simply to rethink the way I was doing it. I've rewritten the makefile to be as follows (trimming out anything unrelated), after reading a lot of Makefile documentation and taking into consideration some comments from MadScientist:
CC = clang++
SRCS = $(wildcard src/*.cc)
OBJECTS = $(patsubst %.cc,$(OBJDIR)/%.o,$(SRCS))
CFLAGS = -g -Wall -Wextra -std=c++11 -MMD
.PHONY: all clean run
all: $(EXECUTABLE)
-include $(OBJECTS:.o=.d)
$(EXECUTABLE): $(OBJECTS)
#mkdir -p gen
$(CC) -o gen/$(EXECUTABLE) $(OBJECTS)
$(OBJDIR)/%.o: %.cc
#mkdir -p $(#D)
$(CC) -c $(CFLAGS) $(CMDFLAGS) -o $# $<
clean:
rm -rf obj obj-2 gen
run:
cd gen && ./$(EXECUTABLE)
From there, I made a couple aliases in my .bash_profile:
alias mfirst="make OBJDIR=obj EXECUTABLE=first"
alias msecond="make OBJDIR=obj-2 CMDFLAGS=-DCOMPILE_FLAG EXECUTABLE=second"
Because the variables are now set outside of any target specification, everything plays nicely. It keeps the object files and the dependencies separate, and the aliases still allow quick usage (including mfirst run, for example).
Feel free to point out any flaws here, but I'm fairly happy with the result.

Why doesn't my make file leave behind object files?

I am new to make files and I put this together with a bit of trial & error. This code is used to compile my c++ program.
My main.cpp file in the same folder as the makefile. I have a lib/ folder that contains the headers main depends on.
The following makefile results in a correct and complete compilation of my code. But I was expecting that I would find *.o objects left behind. (Note that I've tried to make both with and without the "clean" rule, and I get the same results both times.)
#
# Makefile
#
CXX = g++
CCFLAGS = -O3 -I/sw/include -L/sw/lib
## /sw/include and /sw/lib contain dependencies for files in my lib/
LDFLAGS = -lpng
OPTS = $(CCFLAGS) $(LDFLAGS)
SOURCES = $(wildcard lib/*.cpp) main.cpp
OBJECTS = $(SOURCES: .cpp = .o)
TARGET = spirals
$(TARGET): $(OBJECTS)
$(CXX) $(OPTS) $^ -o $#
.PHONY: depend
depend:
g++ -MM $(SOURCES) > depend
## generate dependencies list
include depend
.PHONY: clean
clean:
rm -f *.o lib/*.o $(TARGET)
Also, in case it matters, I'm on MacOSX and my program is designed in xcode. (I know that xcode has its own build flow, but I'm designing a command-line program for a linux system and I'd like to test compilation & linking in a bash environment instead of only going through xcode.)
Questions:
Am I correct to expect makefiles to produce *.o files that stick around once the main target has been created?
If so, why doesn't my makefile do this?
If you observe what command your $(TARGET) rule causes to be run:
g++ -O3 -I/sw/include -L/sw/lib -lpng lib/bar.cpp lib/foo.cpp main.cpp -o spirals
you'll see that $(OBJECTS) in fact contains *.cpp files, and there are no *.o files sticking around because you haven't asked for any.
The problem is here:
OBJECTS = $(SOURCES:.cpp=.o)
In your GNU makefile as written, this substitution reference is written with excess spaces, so never matches anything and $(OBJECTS) ends up the same as $(SOURCES). Rewrite it as above and it'll do what you expect.
(Other notes: -lpng needs to go at the end of the link command to work in general, so you should introduce another make variable (traditionally called $(LDLIBS)) so as to arrange that. Especially as someone new to makefiles, you would do better to spell out your dependencies explicitly rather than playing games with $(wildcard) and a computed $(OBJECTS). -I options are needed during compilation while -L options are used during linking, so it would be good to arrange separate $(CXXFLAGS)/$(LDFLAGS) variables used in separate rules so they are only added when required.)

How to write a simpler makefile for a lot of single-c-file programmes?

I want to write a lot of tiny example programmes for one same library, each needs gcc $(OtherOpt) -o xxx -lthelibname xxx.c.
How to write a Makefile without dozens of tagret lines ?
Pattern rules are your friend for these situations. As long as your targets all match a predictable pattern -- and they do in this case, as they are all of the form "create foo from foo.c" -- you can write a single pattern rule that will be used for all of the targets:
OtherOpt=-Wall -g
all: $(patsubst %.c,%,$(wildcard *.c))
%: %.c
gcc $(OtherOpt) -o $# -lthelibname $<
Now you can either run simply make to build all your apps, or make appname to build a specific app. Here I've created a single pattern rule that will be used anytime you want to create something from something.c. I used the $# automatic variable, which will expand to the name of the output, and the $< variable, which will expand to the name of the first prerequisite, so that the command-line is correct regardless of the specific app being built. Technically you don't need the all line, but I figured you probably didn't want to always have to type in the name(s) of the apps you want to build.
Also, technically you can probably get away without having any of this makefile, because GNU make already has a built-in pattern rule for the %: %.c relationship! I mention this option only for completeness; personally, I prefer doing things the way I've shown here because it's a little bit more explicit what's going on.
%.o: %.c
gcc $(OtherOpt) -c -o $# -lthelibname $<
That compiles all .c files to their .o files (object code) of the same base name. Then in your actual target(s), you would include all necessary .o files as dependencies and use gcc $(OtherOpt) -o $# $^ -lthelibname, assuming I'm not misunderstanding how your build is set up.
Some versions of make also support the suffix rule .c.o to be ALMOST the same thing as %.o: %.c, but the suffix rules can't have any dependencies. Writing .c.o: foo.h tells make to compile "foo.h" to "foo.c.o" rather than requiring "foo.h" as a dependency of any file with a .c suffix as %.o: %.c foo.h would correctly do.
I learnd from http://sourceforge.net/projects/gcmakefile/
LDLIB = -lpthread
LDFLAGS = -Wl,-O1 -Wl,--sort-common -Wl,--enable-new-dtags -Wl,--hash-style=both $(LDLIB)
SRCDIRS =
SRCEXTS = .c .C .cc .cpp .CPP .c++ .cxx .cp
CFLAGS = -pipe -march=core2 -mtune=generic -Wfloat-equal \
#-Wall -pedantic
ifeq ($(SRCDIRS),)
SRCDIRS = .
endif
SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
TARGET = $(addprefix bin/,$(basename $(SOURCES)))
all: $(TARGET)
ls -l $(TARGET)
bin/%: %.c dir
gcc $(CFLAGS) $(LDFLAGS) -o $# $<
dir:
#-mkdir bin
.PHONY : clean
clean:
-rm $(TARGET)
-rmdir bin

Resources