I am writing a simple kernel and all is going well so far.
I am using a Makefile to build the system through the shell.
However, I wish to move and reorganise the file structure but, my the makefile uses absolute linking.
How can I refactor this to compile all .cpp/.c files and .s files to an out folder and link them, without needing to define each folder path?
CC = ~/opt/cross/bin/i386-elf-g++
AS = ~/opt/cross/bin/i386-elf-as
LNFLAGS = -T linker.ld -melf_i386
CCFLAGS = -c -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions
ASFLAGS = -c
CTMP = $(wildcard src/kernel/*.cpp)
ATMP = $(wildcard src/kernel/arch/i386/*.s)
CFILE = $(subst src/kernel/, ,$(CTMP))
AFILE = $(subst src/kernel/arch/i386/, ,$(ATMP))
CSRC = $(CFILE:.c=)
ASRC = $(AFILE:.s=)
OUT = $(wildcard out/*.o)
all: ccompile acompile link
ccompile:
for file in $(CSRC) ; do \
$(CC) $(CCFLAGS) src/kernel/$$file -o out/$$file.o ; \
done
acompile:
for file in $(ASRC) ; do \
$(AS) $(ASFLAGS) src/kernel/arch/i386/$$file.s -o out/$$file.o ; \
done
link:
ld $(LNFLAGS) -o latest.bin $(OUT)
Use the vpath directive to specifiy the source directories.
TARGETS := latest.bin
LD := ld
LDFLAGS := -T linker.ld -melf_i386
CC := ~/opt/cross/bin/i386-elf-g++
CCFLAGS := -c -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions
AS := ~/opt/cross/bin/i386-elf-as
ASFLAGS := -c
vpath %.cpp src/kernel
vpath %.s src/kernel/arch/i386
SOURCES := $(wildcard *.cpp) $(wildcard *.s)
OBJECTS := $(addsuffix .o, $(basename $(notdir $(SOURCES))))
all: $(TARGETS)
out/%.o: %.cpp
$(CC) $(CCFLAGS) -o $# $<
out/%.o: %.s
$(AS) $(ASFLAGS) -o $# $<
latest.bin: $(OBJECTS)
$(LD) $(LDFLAGS) -o $# $^
Related
I'm currently using MinGW64, G++, and a makefile to compile my c++ project on VSCode. I have two src directories src and src/vendor/imGui containing .cpp files that I compile. As of now, the makefile is able to compile both src folders. However, the .o files are outputted in their respective src folders. How can I make it so that every .o file generated gets sent to one specific folder/directory?
Current Makefile:
CXX = g++
CXXFLAGS := -std=c++17 -Wall -Wextra -g
LFLAGS += -LC:/mingw64/x86_64-w64-mingw32/bin
LFLAGS += -LC:/mingw64/x86_64-w64-mingw32/lib
OUTPUT := output
SRC := src
SRC += src/vendor/imGui
INCLUDE := include
LIB := lib
ifeq ($(OS),Windows_NT)
MAIN := main.exe
SOURCEDIRS := $(SRC)
INCLUDEDIRS := $(INCLUDE)
LIBDIRS := $(LIB)
FIXPATH = $(subst /,\,$1)
RM := del /q /f
MD := mkdir
else
MAIN := main
SOURCEDIRS := $(shell find $(SRC) -type d)
INCLUDEDIRS := $(shell find $(INCLUDE) -type d)
LIBDIRS := $(shell find $(LIB) -type d)
FIXPATH = $1
RM = rm -f
MD := mkdir -p
endif
INCLUDES := $(patsubst %,-I%, $(INCLUDEDIRS:%/=%))
INCLUDES += -IC:/Users/kimda/Desktop/Projects/C++/Libraries/glm
INCLUDES += -IC:/mingw64/x86_64-w64-mingw32/include
INCLUDES += -IC:/Users/kimda/Desktop/Projects/C++/OpenGL/src/vendor/imGui
LIBS := $(patsubst %,-L%, $(LIBDIRS:%/=%))
LIBS += -lglew32
LIBS += -lopengl32
LIBS += -lglfw3
LIBS += -lgdi32
LIBS += -lglu32
SOURCES := $(wildcard $(patsubst %,%/*.cpp, $(SOURCEDIRS)))
OBJECTS := $(SOURCES:.cpp=.o)
OUTPUTMAIN := $(call FIXPATH,$(OUTPUT)/$(MAIN))
all: $(OUTPUT) $(MAIN)
#echo Building complete!
$(OUTPUT):
#$(MD) $(OUTPUT)
$(MAIN): $(OBJECTS)
#$(CXX) $(CXXFLAGS) $(INCLUDES) -o $(OUTPUTMAIN) $(OBJECTS) $(LFLAGS) $(LIBS)
.cpp.o:
#$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#
.PHONY: clean
clean:
#$(RM) $(OUTPUTMAIN)
#$(RM) $(call FIXPATH,$(OBJECTS))
#echo Cleanup complete!
run: clean all
#./$(OUTPUTMAIN)
#echo Executing complete!
If I understand you correctly you want to send all object files to some 'build' directory.
I usually do something like this
BUILDDIR := build
[...]
OBJECTS := $(addprefix $(BUILDDIR)/,$(SOURCES:.cpp=.o))
[...]
and then change your
.cpp.o:
#$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#
to
$(BUILDDIR)/%.o: %.cpp
#$(MD) $(dir $#)
#$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#
1. My file structure is:
build/
include/
-Sort.h
src/
-Sort.cpp
-main.cpp
2. My Makefile:
C++ = g++
SRCPATH := ./src
BUILDPATH := ./build
SORTINCPATH := ./include
TARGET := $(BUILDPATH)/sort
CPPFLAGS := -c -g -Wall -O0
INCPATH := -I./ -I$(SORTINCPATH)
CPPFILES += $(wildcard $(SRCPATH)/*.cpp)
CFILES += $(wildcard $(SRCPATH)/*.c)
HEADFILES += $(wildcard $(SORTINCPATH)/*.h)
CPPOBJS += $(CPPFILES:.cpp=.o)
COBJS += $(CFILES:.c=.o)
.PHONY : all
all: $(TARGET)
$(TARGET): $(CPPOBJS) $(COBJS)
$(C++) $(CPPFLAGS) -o $# $(CPPOBJS) $(COBJS)
%.o : %.c $(HEADFILES)
$(C++) $(CPPFLAGS) $(INCPATH) $< -o $#
%.O : %.cpp $(HEADFILES)
$(C++) $(CPPFLAGS) $(INCPATH) $< -o $#
.PHONY : clean
clean:
-rm $(TARGET) $(COBJS) $(CPPOBJS)
3. Sort.h
sort.h
4. Sort.cpp
sort-1.cpp
sort-2.cpp
5. When I run make, it shows the following:
g++ -c -g -Wall -O0 -c -o src/Sort.o src/Sort.cpp
and says "src/Sort.cpp:3:18: fatal error: Sort.h: no such file or directory".
I hope you can help me find out where the problem is.
Thank you so much!
I have a C++ project with the following structure:
/Project
Makefile
/src (.cpp source files)
...
/include (.h header files)
...
/libs
...
/build (.o object files)
...
/tests (target .cpp files I want to compile)
test1.cpp
test2.cpp
test3.cpp
...
/bin (output directory for compiled files)
...
For the tests inside my test file, I would like to be able to
Compile them individually, e.g. "make test1", "make test2"
Compile them all at once
But I would like to be able to do this without needing to define new variables (e.g. TARGET1, TARGET2,...) for each new test file, nor add a bunch of new lines to my makefile for each new test file.
For example, right now I have something like:
CXX = g++
SRC_DIR = ./src
BUILD_DIR = ./build
LIB = -I libs
INC = -I include
SRCS = $(shell find $(SRC_DIR) -type f -name *.cpp)
OBJS = $(patsubst $(SRC_DIR)/%, $(BUILD_DIR)/%, $(SRCS:.cpp=.o))
TARGET1 ?= test1.cpp
TARGET2 ?= test2.cpp
TARGET3 ?= test3.cpp
all: $(OBJS)
$(CXX) ./tests/$(TARGET1).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET1)
$(CXX) ./tests/$(TARGET2).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET2)
$(CXX) ./tests/$(TARGET3).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET3)
$(TARGET1): $(OBJS)
$(CXX) ./tests/$(TARGET1).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET1)
$(TARGET2): $(OBJS)
$(CXX) ./tests/$(TARGET2).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET2)
$(TARGET3): $(OBJS)
$(CXX) ./tests/$(TARGET3).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET3)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $# $<
which does the job, but isn't very scalable. How could I do this scalably?
Make has some more tricks that you can use (not tested):
CXX = g++
SRC_DIR = src
BUILD_DIR = build
TEST_DIR = tests
BIN_DIR = bin
LIB = -I libs
INC = -I include
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
TESTS = $(wildcard $(TEST_DIR)/*.cpp)
TARGETS = $(patsubst $(TEST_DIR)/%.cpp,$(BIN_DIR)/%,$(TESTS))
all: $(TARGETS)
$(TARGETS): $(BIN_DIR)/%: $(OBJS)
$(CXX) $(TEST_DIR)/$*.cpp $(LIB) $(INC) $^ -o $#
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $# $<
The main trick here is the static pattern rule for $(TARGETS): in the recipe $* expands as the stem of the pattern. The other tricks are a simpler use of patsubst and the use of wildcard instead of the less efficient shell find. Note that this last one works only if your source files are flat in src, not if they are organized in a hierarchy of sub-directories.
But this does not answer your most tricky request: a way to invoke make testX instead of make bin/testX. So, here is the most tricky part:
SHORTERTARGETS = $(patsubst $(TEST_DIR)/%.cpp,%,$(TESTS))
.PHONY: $(SHORTERTARGETS)
# $(1): short target
define TARGETS_rule
$(1): $(BIN_DIR)/$(1)
endef
$(foreach t,$(SHORTERTARGETS),$(eval $(call TARGETS_rule,$(t))))
You can even use this foreach-eval-call to factorize other parts of your Makefile:
CXX = g++
SRC_DIR = src
BUILD_DIR = build
TEST_DIR = tests
BIN_DIR = bin
LIB = -I libs
INC = -I include
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
TESTS = $(wildcard $(TEST_DIR)/*.cpp)
TARGETS = $(patsubst $(TEST_DIR)/%.cpp,$(BIN_DIR)/%,$(TESTS))
SHORTERTARGETS = $(patsubst $(TEST_DIR)/%.cpp,%,$(TESTS))
.PHONY: all $(SHORTERTARGETS)
all: $(TARGETS)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $# $<
# $(1): short target
define TARGETS_rule
$(1): $(BIN_DIR)/$(1)
$(BIN_DIR)/$(1): $(OBJS)
$(CXX) $(TEST_DIR)/$(1).cpp $(LIB) $(INC) $$^ -o $$#
endef
$(foreach t,$(SHORTERTARGETS),$(eval $(call TARGETS_rule,$(t))))
The most difficult to understand in this last version is the need of $$in the recipe (double expansion). But here the GNU make manual is your friend.
I have seen some examples of using makefile with multiple source directories but still could not implement it to my makefile.
Currently I have all source files at /src/ folder and I would like to be able compile subfolders in /src/ such as /src/modules.
I am using:
NAME = 'AI'
SRC = src
TGT = obj
PRG = application
INCLUDES = -Iinclude ...
LIBRARIES = -L ...
CXXFLAGS = -O2 -std=c++0x $(INCLUDES) $(LIBRARIES)
SOURCES = $(wildcard $(SRC)/*.cpp)
ENDFLAGS = -ljvm -lcurl
NOWARNINGS = -Wno-unused-variable -Wno-unused-result
OBJS = $(addprefix $(TGT)/, $(notdir $(SOURCES:.cpp=.o)))
$(TGT)/%.o: $(SRC)/%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $# $(NOWARNINGS)
$(PRG)/$(NAME): $(OBJS)
$(CXX) $(LIBRARIES) $(OBJS) -o $# $(ENDFLAGS) $(NOWARNINGS)
I am trying to build excutables for multiple files which are built in the same way. When i run make all the excutables should be generated. I am getting error at prerequisites part of the macro.
CXX = g++
CXX_FLAGS = -g -Wall
LD_FLAGS =
INC_DIR = -I/my/path/include
SRC_DIR = .
LIB_DIR = -L$/my/path/lib
OBJ_DIR = obj
EXE_DIR = exe
SRCS := $(foreach s_dir, $(SRC_DIR), $(wildcard $(s_dir)/*.cpp))
OBJS := $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRCS))
EXES := $(patsubst $(SRC_DIR)/%.cpp, $(EXE_DIR)/%.out, $(SRCS))
all: create_directories create_objects create_exes
create_directories:
#echo "Creating $(OBJ_DIR) and $(EXE_DIR)..."
#mkdir -p obj
#mkdir -p exe
create_objects:
$(foreach b_dir, $(OBJ_DIR), $(eval $(call build-objects, $(b_dir))))
create_exes:
$(foreach ot, $(EXE_DIR), $(eval $(call build-exes, $(ot))))
define build-objects
$1/%.o: %.cpp
$(CXX) $(CXX_FLAGS) $(INC_DIR) -MMD -MP -c $$< -o $$#
endef
define build-exes
$1/%.out:obj/%.o
$(CXX) $(LD_FLAGS) -o $# $(OBJS) $(LIB_DIR) -lmylib
endef
Is this a right way to do generate multiple exes or any other simple way?
If I'm reading this makefile right, then it's much too complicated.
First let's have a rule to build object files:
$(OBJ_DIR)/%.o: %.cpp
$(CXX) $(CXX_FLAGS) $(INC_DIR) -MMD -MP -c $< -o $#
Now if we're not sure about the existence of obj/, we could add a rule to create it, but for the moment let's just put in a failsafe (we'll come back to this later):
$(OBJ_DIR)/%.o: %.cpp
#mkdir -p $(OBJ_DIR)
$(CXX) $(CXX_FLAGS) $(INC_DIR) -MMD -MP -c $< -o $#
And a similar rule to build the executables:
$(EXE_DIR)/%.out: $(OBJ_DIR)/%.o
#mkdir -p $(EXE_DIR)
$(CXX) $(LD_FLAGS) -o $# $^ $(LIB_DIR) -lmylib
And finally (at the top) some variables, the lists of files, and the all rule:
CXX = g++
CXX_FLAGS = -g -Wall
LD_FLAGS =
INC_DIR = -I/my/path/include
SRC_DIR = .
LIB_DIR = -L$/my/path/lib
OBJ_DIR = obj
EXE_DIR = exe
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
EXES := $(patsubst $(SRC_DIR)/%.cpp, $(EXE_DIR)/%.out, $(SRCS))
# Let the object files take care of themselves
all: $(EXES)
That's all you need. Once this is working perfectly, we can discuss refinements like rules for building directories.