I have the following folder structure:
├── build
├── external
│ ├── build
│ ├── lib1
│ │ ├── lib1Classes.cc
│ │ └── lib1Classes.h
│ ├── lib2
│ │ ├── lib2Classes.cc
│ │ └── lib2Classes.h
│ ├── lib3
│ │ ├── lib3Classes.cc
│ │ └── lib3Classes.h
│ └── Makefile
├── include
│ ├── SomeClass.h
│ └── SomeOtherClass.h
├── Makefile
└── src
├── main.cpp
├── SomeClass.cc
└── SomeOtherClass.cc
I am trying to first compile libXClasses.cc and libXClasses.h into ./external/build/libX.o, then combine all libX.o into an ./external/build/external.so.
In step 2 I'd like to compile SomeClass.h and SomeClass.cc into ./build/SomeClass.o and SomeOtherClass.h, SomeOtherClass.cc into ./build/SomeOtherClass.o. Finally I want to link ./external/build/external.o and ./build/*.o into a binary in ./build.
I am however already failing in step 1. My idea for ./external/Makefile was something like this:
CXX = g++ -std=c++11
TARGET ?= external.so
BUILD_DIR ?= ./build
# get all source files
SRCS = $(shell find . -name *.cc -or -name *.cpp -or -name *.h)
# get the name of all directories that contain at least one source file
SRC_DIRS ?= $(foreach src,$(SRCS),$(shell dirname $(src)))
# remove duplicate directories
SRC_DIRS := $(shell echo $(SRC_DIRS) | xargs -n1 | sort -u | xargs)
# define one target object file foreach .cc source file
OBJS := $(foreach srcd,$(SRC_DIRS),$(BUILD_DIR)/$(patsubst %.cc,%.o,$(shell find $(srcd) -name *.cc -printf "%f\n")))
# rule to build ./external/build/external.so
$(BUILD_DIR)/$(TARGET): $(OBJS)
$(CXX) -shared $(OBJS) -o $#
# no idea how to build libX.o in one rule
$(BUILD_DIR)/%.o: %.cc %.h
$(CXX) -c -fpic $< -o $#
This does not work as in the last rule I am not specifying where the correct .cc and .h come from. But I don't know how I could do that at all. Do I have to write a rule for each libX directory separately? What if I have 10 or 20 libX directories?
Cheers!
Step 1: create a list of the libX directories (because no one wants to maintain a list like that by hand):
LIBS := $(wildcard external/lib*)
Step 2: create a list of the source files:
LIB_SRCS := $(notdir $(wildcard $(addsuffix /*.cc, $(LIBS))))
(I've removed the paths because they're a pain; there's more than one way to do this.)
Step 3: create a list of desired object files:
OBJS := $(patsubst lib%Classes.cc, external/build/lib%.o, $(LIB_SRCS))
Step 4: write a rule to build these files:
vpath %.cc $(LIBS)
$(OBJS): external/build/lib%.o: lib%Classes.cc
$(CXX) -c -fPIC -I$(dir $<) $< -o $#
(Step 5: write a rule to build the library, but you already have that.)
One could do more. This makefile does not detect the fact that libN.o depends on libNClasses.h. It is possible to set that up, but it's a little complicated, and this is enough for one day.
Related
This is the command I'm trying to run
g++ mario_game/main.cpp mario_game/game.cpp mario_game/mario.cpp dream.cpp -lSDL2 -lSDL2_ttf -lSDL2_mixer -lSDL2_image -std=c++11 -I DreamEngine/DreamEngine2/include -o mario
Here's the directory structure
DreamEngine
└── DreamEngine2
├── 8bit.ttf
├── a.out
├── dream.cpp
├── hello.cpp
├── include
│ └── dream.h
├── LICENSE
└── mario_game
├── game.cpp
├── game.h
├── globalvars.h
├── main.cpp
├── mario.cpp
└── mario.h
Any help will be appreciated. :)
I tried the comment that is said above and it says include not found.
I have this makefile
# Compiler and flags
CC = g++
CFLAGS = -Iinclude
# Source and object files
SOURCES = $(wildcard src/*.cpp)
OBJS = $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
# Dependency files
DEPS = $(patsubst src/%.cpp,obj/%.d,$(SOURCES))
# Include dependency files
-include $(DEPS)
# Build object files from source files
obj/%.o: src/%.cpp
$(CC) -c -o $# $< $(CFLAGS)
$(CC) -MM -MT $# -MF $(patsubst %.o,%.d,$#) $<
# Build library from object files
libui.a: $(OBJS)
ar rcs $# $^
ranlib $#
copy vui.hpp include/vui.hpp
# Clean object files and library
.PHONY: clean
clean:
del obj\*.o obj\*.d libui.a
and this is my workspace:
workspace
├── include
│ ├── UI_Button.hpp
│ ├── UI_CheckBox.hpp
│ ├── UI_Console.hpp
│ ├── UI_ScrollBar.hpp
│ ├── UI_Slider.hpp
│ ├── UI_TextBox.hpp
│ └── vui.hpp
├── src
│ ├── UI_Button.cpp
│ ├── UI_CheckBox.cpp
│ ├── UI_Console.cpp
│ ├── UI_ScrollBar.cpp
│ ├── UI_Slider.cpp
│ └── UI_TextBox.cpp
├── obj
│ ├── UI_Button.o
│ ├── UI_CheckBox.o
│ ├── UI_console.o
│ ├── UI_ScrollBar.o
│ ├── UI_Slider.o
│ └── UI_TextBox.o
├── libui.a
└── Makefile
Now that makefile has built everything I got an error
copy vui.hpp include/vui.hpp
The system cannot find the file specified.
make: *** [Makefile:24: libui.a] Error 1
and when I try to remake I need to delete everything because it only checks UI_Button.o and says it is up to date even if I change any other .hpp or .cpp file it doesn't want to rebuild. Is there a a way I can fix these two errors? the vui.hpp just includes all other headers.
Not sure what copy or del is, but I assume copy a b copies a file a to b. However, this recipe:
# Build library from object files
libui.a: $(OBJS)
ar rcs $# $^
ranlib $#
copy vui.hpp include/vui.hpp
does not depend on vui.hpp, nor do I see any rule to create vui.hpp in your source-root, nor do I see it listed in the files you state you have in your source tree. So, there just is no such file.
If you want to hang on to that command, don't have it running in a completely unrelated recipe. Have an extra recipe for it:
include/vui.hpp: vui.hpp
copy vui.hpp include/vui.hpp
In my C++ project the sources are organized inside a src directory. Inside the src directory are sub directories which all contain headers and source files, e.g.
project
├── Makefile
│
├── MyBinary
│
├── src
│ │
│ ├── main.cpp
│ │
│ ├── Application
│ │ │
│ │ ├── Application.h
│ │ └── Application.cpp
│ │
│ │
│ └── Tasks
│ ├── BackgroundWorker.h
│ └── BackgroundWorker.cpp
│
└── obj
├── Application.o
└── BackgroungWorker.o
I'm trying to create a Makefile so that all object files are created inside obj directory and the executable MyBinary is created above the src directory at the same level as the Makefile is.
It hasn't to be too complicated or automated. I don't mind manually specifying each .cpp and .h file in the Makefile.
But I'm new to Makefiles and unfortunately I'm struggling with this attempt:
CXX=c++
CXXFLAGS=-Wall -Os -g0
# Name of the output binary
APPNAME=MyBinary
# Source root directory
SRC_ROOT=src
# Object file directory
OBJ_DIR=obj
DEPS=$(SRC_ROOT)/Application/Application.h \
$(SRC_ROOT)/Tasks/BackgroundWorker.h
_OBJ=$(SRC_ROOT)/Application/Application.o \
$(SRC_ROOT)/Tasks/BackgroundWorker.o\
$(SRC_ROOT)/main.o
OBJ=$(patsubst %,$(OBJ_DIR)/%,$(_OBJ))
# This rule says that the .o file depends upon the .c version of the
# file and the .h files included in the DEPS macro.
$(OBJ_DIR)/%.o: %.cpp $(DEPS)
$(CXX) -c -o $# $< $(CXXFLAGS)
# Build the application.
# NOTE: The $# represents the left side of the colon, here $(APPNAME)
# The $^ represents the right side of the colon, here $(OBJ)
$(APPNAME): $(OBJ)
$(CXX) -o $# $^ $(CXXFLAGS)
clean:
rm -f $(OBJ_DIR)/*.o $(APPNAME)
The error when calling make is: Fatal error: can't create obj/src/Application.o: File or directory not found.
Can anyone help?
OBJ=$(patsubst %,$(OBJ_DIR)/%,$(_OBJ)) prepends obj/ to the words of _OBJ. You want to replace the src by obj something which you can do with
OBJ=$(patsubst $(SRC_ROOT)/%,$(OBJ_DIR)/%,$(_OBJ))
Note that the directory structure you get expect subdirectories Application and Tasks to obj you either have to create them manually before calling make or updating the Makefile to create them.
Here is something which behaves as I expect when the directory structure is pre-created.
APPNAME=MyBinary
SRC_ROOT=src
OBJ_DIR=obj
DEPS=$(SRC_ROOT)/Application/Application.h \
$(SRC_ROOT)/Tasks/BackgroundWorker.h
_OBJ=$(SRC_ROOT)/Application/Application.o \
$(SRC_ROOT)/Tasks/BackgroundWorker.o\
$(SRC_ROOT)/main.o
OBJ=$(patsubst $(SRC_ROOT)/%,$(OBJ_DIR)/%,$(_OBJ))
$(OBJ_DIR)/%.o: $(SRC_ROOT)/%.cpp $(DEPS)
echo Making $# from $<
touch $#
$(APPNAME): $(OBJ)
echo Making $# from $^
touch $#
Note that in practice you have to be finer with the dependencies and probably have them to be generated by the compiler (see -MM and similar options for g++), here you recompile everything when you change an header.
I am trying to create the following directory structure for a C++ project.
├── Project
├── Makefile
│ ├── build/
│ ├── src
│ │ ├── include/
│ │ ├── cpp/
│ │ loader.s
│ │ linker.ld
I also want to compile each .cpp file separately into the build directory and link in a different target.
I am having trouble with the wildcard to do this:
BUILD = ./build/
OBJS = $(patsubst src/cpp/%.cpp,build/%.o,$(wildcard src/cpp/*.cpp))
CPPFLAGS = -I ./src/include -Wfatal-errors -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore
$(BUILD)kernel.elf: $(BUILD)loader.o $(OBJS)
$(ARMGNU)-ld -T ./src/linker.ld -o $# $^
$(ARMGNU)-objdump -D $(BUILD)kernel.elf > $(BUILD)kernel.list
$(BUILD)%.o: ./src/%.s
$(ARMGNU)-as $(AFLAGS) -c -o $# $^
$(BUILD)%.o: ./src/cpp/%.cpp
$(ARMGNU)-gcc $(CPPFLAGS) -c -o $# $^
The build/%.o's are never built so the link step gets an empty $(OBJS). What's the correct syntax for this?
Your BUILD variable is set to ./build/, while object files in OBJ start with build/. After expansion rules look like:
./build/kernel.elf: ./build/loader.o build/...
./build/%.o: ./src/%.s
That additional ./ prefix affects rule matching by make, because paths aren't normalized.
The fix is as simple as making prefixes in target goals and prerequisites match by setting:
BUILD = build/
I'm trying to run this makefile, and run into an issue. Make tells me
"No rule to make target 'UDP_Server.o', needed by 'SendRawData',
Since I've given it the working directories of the files however, shouldn't the rule for %.o file work just fine? I'm launching make within the /thing/asset/src directory, and I don't care where it puts the o files or the program, as long as I can access them. Here's my makefile:
CC = g++
INC += -I/home/pi/thing/
INC += -I/home/pi/thing/Asset/src/
INC += -I/home/pi/thing/Server/src/
INC += -I/home/pi/thing/Shared/NetworkInterface/src/
INC += -I/home/pi/mercuryapi/c/src/
LIB = /home/pi/mercury/c/src/api/
CFLAGS = -std=c++11 -Wno-write-strings
LDFLAGS = -L$(LIB) -static -l libmercuryapi
SOURCES += UDP_Client.cpp
SOURCES += UDP_Server.cpp
SOURCES += rawData.cpp
SOURCES += packetMethods.cpp
SOURCES += parseData.cpp
SOURCES += SendRawData.cpp
OBJECTS = $(SOURCES:.cpp=.o)
DEPS = UDP_Client.h
DEPS += UDP_Server.h
DEPS += packet.h
DEPS += rawData.h
DEPS += packetMethods.h
DEPS += parseData.h
DEPS += tm_reader.h
default: SendRawData
%.o: %.cpp $(SOURCES) $(DEPS)
$(CC) $(CFLAGS) $(INC) -c $< -o $#
SendRawData: $(OBJECTS)
$(CC) $(CFLAGS) $(LDFLAGS) $(INC) $< -o SendRawData
client: cmain.cpp UDP_Client.cpp
$(CC) $(CFLAGS) cmain.cpp UDP_Client.cpp -o client
.cpp.o:
$(CC) $(CFLAGS) $(INC) -c $< -o $#
.PHONY: clean
clean:
rm *.o
If it helps at all, here is the directory structure visualized:
/home/pi/thing/
├── Asset
│ ├── README.txt
│ └── src
│ ├── makefile
│ ├── README.txt
│ ├── SendRawData.cpp
│ ├── UDP_Client.cpp
│ └── UDP_Client.h
├── Server
│ └── src
│ ├── README.txt
│ ├── server
│ ├── UDP_Server.cpp
│ ├── UDP_Server.h
│ └── UDP_Server.o
└── Shared
├── NetworkInterface
│ ├── README.txt
│ └── src
│ ├── header.h
│ ├── packet.h
│ ├── packetMethods.cpp
│ ├── packetMethods.h
│ ├── parseData.cpp
│ ├── parseData.h
│ ├── rawData.cpp
│ ├── rawData.h
│ └── testing.cpp
└── README.txt
Make cares where you put the files. You need to tell make where the source files are located.
The ugly, tedious, but explanatory solution is to add the path when specifying the dependency. Instead of
SOURCES += UDP_Client.cpp
write
SOURCES += ../../Server/src/UDP_Client.cpp
The beautiful and simple solution is to use makes VPATH variable:
https://www.gnu.org/software/make/manual/html_node/General-Search.html
For example
VPATH = "../../Server/src/UDP_Client.cpp:<list of : separated paths>"
This solution might only work if your using gnu make.