Compile a program with source files in different folders, with makefile - makefile

So I have been trying to use the answers and the idea of this published question: Makefile: Compiling from directory to another directory
In the following excerpt code, you can see the definition of the directories, for sources and compilation objects.
all : Mpois Mkvz MBJ Mlid
# Definitions
COMPILER := gfortran -O3
LIBS := -g -fbounds-check -ffast-math -lm
# Directories of object code
OBJDIR = objects
SRCDIR = src
SOURCES := $(SRCDIR)/lbm_const.f90 $(SRCDIR)/BORDERS.f90 $(SRCDIR)/CONVERGENCE.f90 $(SRCDIR)/FILESIO.f90 $(SRCDIR)/LBM.f90
OBJECTS := $(OBJDIR)/lbm_const.o $(OBJDIR)/BORDERS.o $(OBJDIR)/CONVERGENCE.o $(OBJDIR)/FILESIO.o $(OBJDIR)/LBM.o
SOURCES_pois := $(SRCDIR)/Main_pois.f90
OBJECTS_pois := $(OBJDIR)/Main_pois.o
# Linking
Mpois: $(OBJECTS) $(OBJECTS_pois)
$(COMPILER) $^ -o $# $(LIBS)
# Compiling
$(OBJECTS): $(OBJDIR)/%.o: %.f90
$(COMPILER) -c $< -o $#
# Compiling
$(OBJECTS_pois): $(OBJDIR)/%.o: %.f90
$(COMPILER) -c $< -o $#
clean:
rm -f $(OBJDIR)/*.o
rm -f $(OBJDIR)/*.mod
rm -f $(SRCDIR)/*.mod
When running the makefile script I get the following error:
make: *** No rule to make target 'lbm_const.f90', needed by 'objects/lbm_const.o'. Stop.
Interesting is to note that when SRCDIR = src changes to SRCDIR = . the makefile compiles even having files in folder src.

Related

make: Cleaner way to refer to object files in subdirectories

I've got a simple program that has sources in its root directory and in subdirectories. I'm using recursive make invocations to build the subdirectory objects. When linking I can use a symbolic name for the objects in the program's root (${OBJECTS}) but not for objects in the subdirectories (*/*.o). Is there a cleaner way to refer to the subdirectory object files than what I've written? I'm using GNU Make 4.1. Here's the (simplified) top-level Makefile:
MAKE = make
CXX = g++
CFLAGS = -O -Wall -D_DEFAULT_SOURCE -D_BSD_SOURCE
LIBS =
PROGRAM = program_name
TOPTARGETS := all clean
SUBDIRS := util command device
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# $(MAKECMDGOALS)
.PHONY: $(TOPTARGETS) $(SUBDIRS)
all: $(PROGRAM)
SOURCES := $(wildcard *.cpp)
OBJECTS := $(SOURCES:.cpp=.o)
$(OBJECTS): %.o: %.cpp %.h
$(PROGRAM): $(OBJECTS) ${SUBDIRS}
$(CXX) -o $(PROGRAM) ${OBJECTS} */*.o $(LIBS)
clean:
rm -f ${OBJECTS} $(PROGRAM)

How can my makefile include subdirectories?

(updated for clarity) (solution added at bottom)
I found a makefile online which builds all the cpp files in that directory and compiles them.
But I can't work out how I can include files inside a subdirectory.
Here's a breakdown of what happens:
I create the files test.cpp & test.hpp and place them inside the sub-directory '/gui' which is contained within my working directory, they contain the function testFunction().
Without including test.hpp, I type "make" into terminal and I receive the error:
:
g++ -c -o main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:6:2: error: 'testFunction' was not declared in this scope
testFunction();
^~~~~~~~~~~~
make: *** [<builtin>: main.o] Error 1
If I include (#include "gui/test.hpp"), I then receive a different error:
:
g++ -c -o main.o main.cpp
g++ main.o -Wall -o testfile
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x14): undefined reference to `testFunction()'
collect2: error: ld returned 1 exit status
make: *** [makefile:34: testfile] Error 1
But if I then add "-I/gui" or (at a guess) "-I./gui" to CFLAGS, I get the exact same error message.
Here's the makefile for reference:
TARGET = testfile
LIBS =
CC = g++
CFLAGS = -g -Wall
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
HEADERS = $(wildcard *.hpp)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
Thanks in advance!
Updated makefile since accepted answer:
(Changes were to include directories, CC replaced with CXX, and %.c replaced with %.cpp)
TARGET = testfile
DIRS =
LDLIBS =
CXX = g++
CXXFLAGS= -g -Wall
# this ensures that if there is a file called default, all or clean, it will still be compiled
.PHONY: default all clean
default: $(TARGET)
all: default
# substitute '.cpp' with '.o' in any *.cpp
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp $(addsuffix /*.cpp, $(DIRS))))
HEADERS = $(wildcard *.h)
# build the executable
%.o: %.cpp $(HEADERS)
$(CXX) $(CXXFLAGS) -c $< -o $#
# if make is interupted, dont delete any object file
.PRECIOUS: $(TARGET) $(OBJECTS)
# build the objects
$(TARGET): $(OBJECTS)
$(CXX) $(OBJECTS) -Wall $(LDLIBS) -o $#
clean:
-rm -f *.o $(addsuffix /*.o, $(DIRS))
-rm -f $(TARGET)
To understand what's happening here you have to look up the definitions of declaration versus definition in C++ (and other languages). You should definitely do that.
A declaration (typically put into a header file) is like the address of your house. If someone wants to send you a letter, they need your address. If your main function wants to call another function like testFunction(), it needs the declaration of the function.
The first error happens because you don't have the header file included, so the compiler doesn't have the declaration of the function you want to call, which means it won't compile your calling function.
But for the letter to actually arrive, you need your actual house. The address is the declaration and your house is the definition... in this case the actual function implementation. That lives in test.cpp file. When you link your code together, the linker (in this scenario I guess the linker is like the postal service :p :) ) will try to link up the call to the definition.
However, you can see that you are not compiling the test.cpp file nor are you linking the object file:
g++ main.o -Wall -o testfile
here we see main.o, but not gui/test.o.
Why not? This line:
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
Matches all *.cpp files and converts them into .o files. But *.cpp matches only files in the current directory, like main.cpp. If you want to put files in a different directory you have to tell make where they are; for example:
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp gui/*.cpp))

makefile can't find include file path even with -I flag

Compiling with Makefile tells me that it can't find path to some include files.
Here's my directory layout:
build (empty directory)
include (directory)
tpu_uarch (directory)
buffer.hpp common.hpp controller.hpp cpu.hpp
dram.hpp interconnect.hpp mmu.hpp unit.hpp weightfetcher.hpp
obj (directory)
tpu_uarch (empty directory)
src (directory)
test_mmu.cpp test_tile.cpp
buffer.cpp common.cpp controller.cpp cpu.cpp
dram.cpp interconnect.cpp mmu.cpp weightfetcher.cpp
Makefile
And here's what Makefile looks like:
TESTTILE := ./build/testtile.exe
TEST3 := ./build/test3.exe
CC := g++
CPP_SUFFIX := cpp
INCLUDE_DIR := -I./include
SRC_DIR = ./src
OBJ_DIR = ./obj
CFLAGS := -g -Wall -std=c++11
LDFLAGS :=
LIBS :=
# all sources
SRC = $(wildcard $(SRC_DIR)/*.$(CPP_SUFFIX))
SRC += $(wildcard $(SRC_DIR)/**/*.$(CPP_SUFFIX))
# objects
OBJ = $(patsubst $(SRC_DIR)/%.$(CPP_SUFFIX), $(OBJ_DIR)/%.o, $(SRC))
DIR = $(dir $(OBJ))
# executables
testtile: dir $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(TESTTILE) $(LIBS)
test3: dir $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $(TEST3) $(LIBS)
dir:
mkdir -p $(DIR)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.$(CPP_SUFFIX)
$(CC) $(INCLUDE_DIR) $(CFLAGS) -c $< -o $#
clean:
rm -rf $(OBJ_DIR)
rm $(TESTTILE)
rm $(TEST3)
When I write make test3 in command line, I get the following error.
mkdir -p ./obj/ ./obj/ ./obj/tpu_uarch/ ./obj/tpu_uarch/ ./obj/tpu_uarch/ ./obj/tpu_uarch/ ./obj/tpu_uarch/ ./obj/tpu_uarch/ ./obj/tpu_uarch/ ./obj/tpu_uarch/
g++ -I./include -g -Wall -std=c++11 -c src/test_tile.cpp -o obj/test_tile.o
src/test_tile.cpp:1:22: fatal error: common.hpp: No such file or directory
compilation terminated.
Makefile:44: recipe for target 'obj/test_tile.o' failed
make: *** [obj/test_tile.o] Error 1
In all of the *.cpp files, they add include files like #include "common.hpp" without adding directory information. As I understand, adding the -I flag in INCLUDE_DIR should solve problems of finding the include files.
I've checked earlier that the code compiles if I put all .cpp and .hpp files in one directory and type g++ -g -Wall -std=c++11 -o test3.exe buffer.cpp common.cpp controller.cpp cpu.cpp dram.cpp interconnect.cpp mmu.cpp weightfetcher.cpp test_mmu.cpp in the command line interface.
In making test3.exe, test_tile.cpp is not used but I don't think that should be a problem.
Is there something I'm missing or should look into?
Any help or push in the right direction would be greatly appreciated.
[Moved from comments]
You're telling g++ to look in ./include but, according to the directory hierarchy shown, common.hpp and the other headers are actually under ./include/tpu_uarch. You need...
INCLUDE_DIR := -I./include/tpu_uarch
For those who came to find an answer... Even after fixing the issue that G.M. pointed out, I still had some minor issues. (Such as conflict in that both test files include the main() function, etc.)
After that, I managed to fix the code to work.
Here is the working version of Makefile.
TESTTILE := ./build/testtile.exe
TESTMMU := ./build/testmmu.exe
CC := g++
CPP_SUFFIX := cpp
INCLUDE_DIR := -I./include/tpu_uarch
SRC_DIR = ./src
OBJ_DIR = ./obj
BUILD_DIR = ./build
CFLAGS := -g -Wall -std=c++11
LDFLAGS :=
LIBS :=
# all sources
SRC = $(wildcard $(SRC_DIR)/*.$(CPP_SUFFIX))
SRC += $(wildcard $(SRC_DIR)/**/*.$(CPP_SUFFIX))
# objects
OBJ = $(patsubst $(SRC_DIR)/%.$(CPP_SUFFIX), $(OBJ_DIR)/%.o, $(SRC))
DIR = $(dir $(OBJ))
# for tests
TESTTILE_OBJ := ./obj/test_tile.o
TESTMMU_OBJ := ./obj/test_mmu.o
# executables
testtile: dir $(OBJ) $(TESTTILE_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) $(TESTTILE_OBJ) -o $(TESTTILE) $(LIBS)
testmmu: dir $(OBJ) $(TESTMMU_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) $(TESTMMU_OBJ) -o $(TESTMMU) $(LIBS)
dir:
mkdir -p $(DIR)
obj/test_tile.o: $(BUILD_DIR)/test_tile.cpp
$(CC) $(INCLUDE_DIR) $(CFLAGS) -c ./build/test_tile.cpp -o ./obj/test_tile.o
obj/test_mmu.o: $(BUILD_DIR)/test_mmu.cpp
$(CC) $(INCLUDE_DIR) $(CFLAGS) -c ./build/test_mmu.cpp -o ./obj/test_mmu.o
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.$(CPP_SUFFIX)
$(CC) $(INCLUDE_DIR) $(CFLAGS) -c $< -o $#
clean:
rm -rf $(OBJ_DIR)
rm $(TESTTILE)
rm $(TEST3MMU)
The directory topology is as follows:
build (directory)
test_mmu.cpp test_tile.cpp
testmmu.exe testtile.exe (executables created after running make)
include (directory)
tpu_uarch (directory)
buffer.hpp common.hpp controller.hpp cpu.hpp
dram.hpp interconnect.hpp mmu.hpp unit.hpp weightfetcher.hpp
obj (directory, all contents here including directory are created after running make)
tpu_uarch (directory)
buffer.o common.o controller.o cpu.o
dram.o interconnect.o mmu.o weightfetcher.o
test_mmu.o
test_tile.o
src (directory)
tpu_uarch (directory)
buffer.cpp common.cpp controller.cpp cpu.cpp
dram.cpp interconnect.cpp mmu.cpp weightfetcher.cpp
Makefile
Hope this helps.

Makefile doesn't find source files

I have tried to make a makefile. I have the following folder structure.
Source
- include
- My headerfiles
- objects
- The object files
- src
- My source files
My problem is that the source files in the src directory isn't found.
My make file looks as the following.
# gcc for C
# g++ for c++
CC = gcc
#compiler flags
# -g adds debugging information to the executebells
# -Wall
CFLAGS = -g -Wall
#target
TARGET = gabe_the_dog_server
#directory for the object files
OBJDIR = ./objects
SRCDIR = ./src
default: $(TARGET)
all: default
HEADERS = $(wildcard include/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) $(CFLAGS) $(LIBS) -o $(OBJDIR)/$#
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
Here:
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
You use the variable SOURCES, but you never define it. You need one more line:
SOURCES = $(wildcard $(SRCDIR)/*.c)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
Instead of using the path to your source files, it's recommended that you put this path in the special variable named VPATH. Then you just mention your source file, like this:
OBJDIR = ./obj
SRCDIR = ./src
VPATH = $(SRCDIR)
OBJECTS = $(addprefix $(OBJDIR)/, foo.o bar.o)
all: $(OBJECTS)
$(OBJDIR)/%.o: %.c
$(cc) ...
GNU make will look in the folders present in VPATH for the files that are prerequisites of a target. Note that this could be a problem if you have multiple folders where you can find multiple times the same file name.
See GNU make VPATH manual. If you need additional examples of VPATH good practices, see this link as well: Mad Scientist: How not to use VPATH

Makefile to support 2 executables

I am trying to update my Makefile to support building a binary of my project, and a binary of some Unit Tests.
My directory structure is the following
|-code/
|--|--src/
|--|--inc/
|
|-tests/
|--|--src/
|--|--inc/
My makefile compiles the binary from code well, but is having some issues with the test. The test folder contains some unit test that tests some classes in code/src/. I have a file main.cpp in code/src/ that contains the main() function, and also another file, called test.cpp in tests/src that contains its own main() function.
This led me to this complicated Makefile:
CC = g++
FLAGS = -g -c -Wall
INCLUDEDIR = -Icode/inc -Itests/inc
BUILDDIR = build
SOURCEDIR = code/src
SOURCES = $(wildcard $(addsuffix /*.cpp,$(SOURCEDIR)))
TEMP_OBJ = $(SOURCES:%.cpp=%.o)
NOT_DIR = $(notdir $(TEMP_OBJ))
OBJECTS = $(addprefix $(BUILDDIR)/, $(NOT_DIR))
TEST_DIR = tests/src
TEST_SOURCES = $(wildcard $(addsuffix /*.cpp,$(TEST_DIR)))
TEST_TEMP_OBJ = $(TEST_SOURCES:%.cpp=%.o)
TEST_NOT_DIR = $(notdir $(TEST_TEMP_OBJ))
TEST_OBJECTS = $(addprefix $(BUILDDIR)/, $(TEST_NOT_DIR))
EXECUTABLE = Client
TEST_EXECUTABLE = TestUnit
all: $(BUILDDIR) $(BUILDDIR)/$(EXECUTABLE) $(BUILDDIR)/$(TEST_EXECUTABLE)
$(BUILDDIR):
mkdir -p $#
$(BUILDDIR)/$(EXECUTABLE): $(OBJECTS)
$(CC) $^ -o $#
$(BUILDDIR)/%.o : code/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $#
$(BUILDDIR)/$(TEST_EXECUTABLE): $(OBJECTS) $(TEST_OBJECTS)
#rm -f $(BUILDDIR)/main.o
$(CC) $^ -o $#
$(BUILDDIR)/%.o : tests/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $#
clean:
rm -rf $(BUILDDIR)
It fails with the error:
g++: error: build/main.o: No such file or directory
make: *** [build/TestUnit] Error 1
Which is because I have the line:
#rm -f $(BUILDDIR)/main.o
but otherwise I would get the error (there is main in main.cpp and test.cpp in code/src/ and tests/code/ respectively):
/tests/src/test.cpp:7: multiple definition of `main'
code/src/main.cpp:6: first defined here
collect2: error: ld returned 1 exit status
There is a lot of duplication in my Makefile, and I would love to get something more succinct that achieves the purpose of building 2 binaries from those 2 folders, although code is shared.
Any help would please be appreciated. Thank you very much!
There are a number of problems with this makefile.
First, there is no rule to build test object files, such as test.o. The only rule for building objects requires that the source be in code/src/; I don't know how you even get far enough to see a linker error.
Let's change the object rule to a static pattern rule:
$(OBJECTS) : $(BUILDDIR)/%.o : code/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $#
Then we can add an additional rule for the test objects:
$(TEST_OBJECTS) : $(BUILDDIR)/%.o : tests/src/%.cpp
$(CC) $(FLAGS) $< $(INCLUDEDIR) -o $#
(Never mind the redundancy for now-- we have to get it working first.)
Now we should see a linker error in this rule:
$(BUILDDIR)/$(TEST_EXECUTABLE): $(OBJECTS) $(TEST_OBJECTS)
...
In that list of prerequisites are two files, main.o and test.o fighting over who gets to define main(). We want test.o, so main.o must go:
$(BUILDDIR)/$(TEST_EXECUTABLE): $(filter-out build/main.o,$(OBJECTS)) $(TEST_OBJECTS)
...
Try this much and tell us the result. Once it's working we can slim it down.

Resources