I have the following Makefile, and I am trying to simplify it. Any ideas?
PROG_NAME=a.out
all: $(PROG_NAME)
"\nBuilt all\n"
$(PROG_NAME): build/file1.o build/file2.o build/file3.o build/file4.0
gcc -o $# $^
#build file1.c and file2.c which are both in ../src directory
build/file%.o: ../src/file%.c
gcc -I ../inc -o $# $<
#build file3.c and file4.c which are both in ../src2 directory
build/file%.o: ../src2/file%.c
gcc -I ../inc -o $# $<
I tried this and it does not work:
PROG_NAME=a.out
all: $(PROG_NAME)
"\nBuilt all\n"
$(PROG_NAME): build/file1.o build/file2.o build/file3.o build/file4.0
gcc -o $# $^
#build ../src/file1.c, ../src/file2.c, ../src2/file3.c, and ../src2/file4.c
build/file%.o: ../src/file%.c ../src2/file%.c
gcc -I ../inc -o $# $<
You cannot simplify it. The only way would be to use makefile metaprogramming to generate the rules via eval or something.
Your attempt will clearly not work, because this:
build/file%.o: ../src/file%.c ../src2/file%.c
gcc -I ../inc -o $# $<
says "for any target build/fileXXX.o that you want to build, you can create it by running this gcc command on the file ../src/fileXXX.c if either of the files ../src/fileXXX.c or ../src2/fileXXX.c are older than the .o". That's obviously not what you want to do.
I was able to simplify it using the make variable VPATH.
http://www.gnu.org/software/make/manual/make.html#General-Search
PROG_NAME=a.out
VPATH=../src:../src2
all: $(PROG_NAME)
"\nBuilt all\n"
$(PROG_NAME): build/file1.o build/file2.o build/file3.o build/file4.0
gcc -o $# $^
build/file%.o: file%.c
gcc -I ../inc -o $# $<
Related
I have Makefile. This runs on FreeBSD with gmake and make. In BSD Make command not output log same with gmake.
$ gmake
compile main.cpp
linking myout
$ make
c++ -O2 -pipe -c main.cpp -o main.o
linking myout
$ cat Makefile
TARGET = myout
default: $(TARGET)
SRCS = main.cpp
OBJS = $(SRCS:%.cpp=%.o)
default: $(BIN)
%.o: %.cpp
#echo compile $<
#$(CXX) -c $< -o $#
$(TARGET): $(OBJS)
#echo linking $#
#$(CXX) $(OBJS) -o $#
clean:
#rm -f $(OBJS) $(TARGET)
According to the FreeBSD make documentation, it doesn't support pattern rules. So your rule here:
%.o: %.cpp
#echo compile $<
#$(CXX) -c $< -o $#
in FreeBSD make is just an explicit rule telling make how to build the literal file %.o from the literal file %.cpp. Since you don't try to build a file named %.o (you're trying to build main.o), this rule is ignored / never used.
It looks like if you want something that will work the same way between both versions of make you'll have to restrict yourself to the POSIX standard suffix rules format, like this:
.SUFFIXES: .cpp .o
.cpp.o:
#echo compile $<
#$(CXX) -c $< -o $#
The default build utilities are different. FreeBSD uses a different implementation of make than GNU/Linux. The respective man pages outline differences.
https://forums.freebsd.org/threads/difference-gmake-gnu-and-freebsd-make.28784/
I am trying to set an if test for a specific file in my Makefile to compile it with different flags:
.f90.o:
ifeq ($<,main.f90)
#echo ok $<
$(F90) -c $< -o $#
else
#echo nope $<
$(F90) $(F90FLAGS) $(DEBUG) $(INCL) -c $< -o $#
endif
..and despite my efforts I am getting only:
nope main.f90
mpif90 -O2 -g -fbacktrace -fPIC -c main.f90 -o main.o
The ifeq conditional you have used is processed by Make at parse time, not when the recipe is executed. The macro $< is empty when your script is parsed so your recipe only ever contains the latter two lines.
One solution is to provide two recipes, one for your special case and then a pattern recipe for the rest:
main.o:main.f90
$(F90) -c $< -o $#
.f90.o:
$(F90) $(F90FLAGS) $(DEBUG) $(INCL) -c $< -o $#
I have this makefile:
src = $(notdir $(wildcard src/*.cpp))
obj = $(src:.cpp=.o)
libname ?= libtest
importlib_flags = -ldl -lboost_filesystem
parser: $(obj)
g++ -o $# $^
%.o: src/%.cpp
ifeq ($<,src/$(libname).cpp)
g++ -fpic -c $(libname).cpp -o $(libname).o
g++ -shared -Wl,-soname,$(libname).so.1 -o $(libname).so.1.0.1 $(libname).o -lc
else
g++ -c $< -o $# $(if $(findstring importlib, $<), $(importlib_flags))
endif
.PHONY: clean
clean:
rm -rf *.o *.so* parser
After I run make, I get this:
g++ -c src/libtest.cpp -o libtest.o
g++ -c src/importlib.cpp -o importlib.o -ldl -lboost_filesystem
g++ -c src/token.cpp -o token.o
g++ -c src/main.cpp -o main.o
g++ -o parser libtest.o importlib.o token.o main.o
First line implies makefile goes to else branch, but it should go to ifeq because $< expands to src/libtest.cpp which is equal to src/$(libname).cpp after being expanded. I don't set libname via command line. Why doesn't it work?
IIRC the expansion happens before the rule is actually run, therefore the $< is probably expanded to empty. I.e. the makefile parses the if/else before it runs the rule.
Then when the rule is run, it has "pre-selected" the else part since when it did the decision $< was not what it is during the rule.
So what you can do is use shell script (I am assuming bash), somthing like:
%.o: src/%.cpp
if [[ "$<" == "src/$(libname).cpp" ]] ; then \
g++ -fpic -c $(libname).cpp -o $(libname).o ; \
g++ -shared -Wl,-soname,$(libname).so.1 -o $(libname).so.1.0.1 $(libname).o -lc ; \
else \
g++ -c $< -o $# $(if $(findstring importlib, $<), $(importlib_flags)) ; \
fi
Note bash/shell vars are written like $${shell_var} and makefile vars are $(make_var) - just incase you need them!
Also note if you want to specifically use BASH add this to the top of your makefile:
SHELL:=/bin/bash
I am trying to add a project's (call it b) code to a different project(call it a). Both projects are compile and run separately. I just copied the folder of project b into project a's folder. In project a's Makefile, I added the lines to compile project b with it. It compiles fine. Now I want to use b's code. But when I try to #include "/bfolder/somefile.h", it cannot find the file. What am I missing about this? If I can just #include "somefileinsamedirectory.h", why can't I do #include "/bfolder/somefile.h"?`
This is a 's Makefile that I have edited to include the irobot_driver code.
INCLUDE = -I/usr/X11R6/include -I/home/sterling/irobot_driver
CC=g++
CFLAGS=-w -D LINUX -fpermissive
CFLAGS_R= -w -D LINUX -O3 -fpermissive
CFLAGS_D=-w -D LINUX -fpermissive
OBJ= obj
OBJ_DEBUG= obj_debug
OBJDIR= release
SRCDIR= src
LDFLAGS= -L/usr/X11R6/lib$(LIBSELECT) -lGL -lfltk -lfltk_gl -lXext -lX11 -lglut -lGLU -lfltk_images
SOURCES_RAW=codeprofiler.cpp gametimer.cpp timer.cpp timeprofile.cpp vector4.cpp matrix.cpp agent.cpp agentcontroller.cpp dummy.cpp evader.cpp pursuer.cpp goal.cpp player.cpp graphdata.cpp graph.cpp cubiccoefs.cpp segment.cpp trajectory.cpp anode.cpp arrayvector4.cpp color.cpp drawcomponent.cpp drawcontroller.cpp flags.cpp global.cpp map_analyzer.cpp minheap.cpp node.cpp quadtree.cpp queue.cpp results.cpp sensor.cpp settings.cpp utility.cpp world.cpp gui.cpp main.cpp logger.cpp parameters.cpp counter.cpp polygon.cpp line.cpp
TARGET:= pursuit_evasion
TARGETD:= pursuit_evasion_d
TARGETP:= pursuit_evasion_p
TARGETW32:= pursuit_evasion_w32
OBJECTS:=$(SOURCES_RAW:.cpp=.o)
OBJECTS:=$(patsubst %.o,$(OBJDIR)/%.o, $(OBJECTS))
SOURCES:=$(SOURCES_RAW)
SOURCES:=$(patsubst %.cpp,$(SRCDIR)/%.cpp, $(SOURCES))
OBJ_DEBUG:=$(SOURCES_RAW:.cpp=.o)
OBJ_DEBUG:=$(patsubst %.o,debug/%.o, $(OBJ_DEBUG))
OBJECTS_P:=$(SOURCES_RAW:.cpp=.o)
OBJECTS_P:=$(patsubst %.o,profile/%.o, $(OBJECTS_P))
OBJDIR=obj
all: $(TARGET)
#--- Release
$(TARGET): $(OBJECTS)
$(CC) -w -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
cd /home/sterling/irobot_driver; sudo make -j2
release/%.o: src/%.cpp
$(CC) -c $< $(CFLAGS_R) -o $#
#--- Debug
debug: $(TARGETD)
$(TARGETD): $(OBJ_DEBUG)
$(CC) -w -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
cd /home/sterling/irobot_driver; sudo make -j2
debug/%.o: src/%.cpp
$(CC) -c -g $< $(CFLAGS)-o $#
#-- Profile
profile: $(TARGETP)
$(TARGETP): $(OBJECTS_P)
$(CC) -w -g -pg -D LINUX $(INCLUDE) $^ -o $# $(LDFLAGS)
profile/%.o: src/%.cpp
$(CC) -c -g -pg $< $(CFLAGS)-o $#
win32: $(TARGETW32)
$(TARGETW32): $(OBJECTS)
$(CC) -w -D WIN32 $(INCLUDE_W32) $^ -o $# $(LDFLAGS)
.PHONY : clean
clean:
rm -f release/*.o
rm -f debug/*.o
rm -f profile/*.o
rm -f $(TARGET) $(TARGETD) $(TARGETP)
cd /home/sterling/irobot_driver; make clean;
The #include "/the/whole/path/to/a/file" that works is -
#include "/home/sterling/irobot_driver/robot_driver_agent.h"
You can, but when you declare the path starting with /some/path/to/file.h it's going to really look for the file at /some/path/to/file.h. If instead you want the bfolder/somefile.h, remove the / from the beginning.
Also, in general, if b is a library that you want to use, it is best to keep it in whatever folder it resides, and include and link using the -I, -L and -l options of gcc, or similar options of other compilers. This way, if you update b you don't need to copy it to every project that uses it.
Try
#include "bfolder/somefile.h"
You are including a leading slash in "/bfolder/somefile.h", which means /bfolder would be in the root directory.
#include "/bfolder/..." would be implying that bfolder is in the root directory of your computer's file system. If bfolder is in the same directory as your source code, then you would just want #include "bfolder/somefile.h"
Why does
$(OBJDIR)\%.o:$(SRDDIR)\%.s
$(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o $#
$(OBJDIR)\%.o:$(SRDDIR)\%.c
$(GCC) -c -g -I$(SRCDIR) $(CFLAGS) $< -o $#
gives warning (says ignoring the first rule)
where as
%.o:%.s
$(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o $#
%.o:%.c
$(GCC) -c -g -I$(SRCDIR) $(CFLAGS) $< -o $#
works fine but I will have all my sources and objs in the same directory.
I would like to put the objs (generated from assembly files and c files) in a separate directory( and I am running make on windows).
Try using forward slashes ("/") instead of backward ones ("\").
The -o flag of GCC determines where the output file are made.
So this may work if you change:
%.o:%.s $(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o $#
TO
%.o:%.s $(GCC) -c -g -I$(SRCDIR) $(ASFLAGS) $< -o myoutputdir/$#