I'm building a project with a structure like this:
- Makefile
- main.cpp
- util.h
- subsrc/
- one.cpp
- two.cpp
And I have my Makefile set up to output to a build directory:
all: $(BIN_FILE)
$(BIN_FILE): $(OBJ_FILES)
mkdir -p $(BIN_DIR)
g++ $^ -o $#
$(OBJ_DIR)/%.o: %.cpp
mkdir -p $(OBJ_DIR)
g++ -c $^ -o $#
$(OBJ_DIR)/subsrc/%.o: subsrc/%.cpp
mkdir -p $(OBJ_DIR)/subsrc
g++ -c $^ -o $#
clean:
rm -rf $(BUILD_DIR)/*
However, I'm seeing this issue when I run g++ manually as well, so I don't think it's related to the Makefile.
I can build from clean and everything works fine. The issue is when I change one of the subsrc files and try to recompile, via make or by running these commands myself:
g++ -c subsrc/one.cpp -o build/obj/subsrc/one.o
g++ build/obj/main.o build/obj/subsrc/one.o build/obj/subsrc/two.o -o build/bin/prog
If I do this, changes made in one.cpp are not reflected in the binary output. If I recompile main.cpp (or, of course, the entire project), it works fine. This is not an issue of g++ not properly overwriting files, since even if I rm build/obj/subsrc/one.o and/or rm build/bin/prog before running the above commands, I still don't see the changes. That makes no sense to me and I have no idea what's happening.
EDIT: I have uploaded a minimum reproducible example here. https://github.com/scatter-dev/so_70242118_min_repro
Reproduction instructions:
Build using make or by running the g++ commands above.
Run the program to ensure it has built correctly.
Change the output of the doWork function in one.cpp. Save to disk.
Rerun make and note that the one.o file is recompiled and prog is recreated with the linker.
Run the program again and see that the output has not changed.
At the suggestion of a commenter, I checked the md5sum of one.o and prog between steps 1 and 4 and they are indeed both the same. This remains the case even if I delete one.o before recompiling. Yes, I am sure that one.cpp is being saved to disk (its md5sum does change, along with the fact that make clean && make will compile using the new changes).
Your problem is that your code is weirdly written and as a result, your makefile is incomplete.
In your main.cpp you have:
#include "subsrc/derived.h"
which is fine but in that header you have:
#include "one.cpp"
#include "two.cpp"
which is extremely bizarre. You pretty much never want to include .cpp files in other source files (or in header files). It's just a bad idea.
In this situation, ALL the content of your program is included into main.cpp and thus appears in your main.o file. Linking in the other objects (one.o and two.o) is useless and unnecessary: they are ignored.
In your makefile, however, you don't list one.cpp or two.cpp as prerequisites of main.o, which means that when you modify these source files main.o is not updated, and so nothing changes. If you remove main.o, then it is recompiled and you get the new behavior.
ETA
You have two options:
You can either put the declaration of the classes into derived.h and put the definition of the doWork() method into the .cpp files. That would look like this:
$ cat main.cpp
#include "subsrc/derived.h"
...
$ cat subsrc/derived.h
#include "../base.h"
class Derived1 : public Base {
public:
void doWork();
};
class Derived2 : public Base {
public:
void doWork();
};
$ cat subsrc/one.cpp
#include <iostream>
#include "derived.h"
void Derived1::doWork() {
std::cout << "I'm Derived1" << std::endl;
}
$ cat subsrc/two.cpp
#include <iostream>
#include "derived.h"
void Derived2::doWork()
{
std::cout << "I'm Derived2" << std::endl;
}
$ cat Makefile
...
$(OBJ_DIR)/main.o : base.h subsrc/derived.h
$(OBJ_DIR)/subsrc/one.o: base.h subsrc/derived.h
$(OBJ_DIR)/subsrc/two.o: base.h subsrc/derived.h
Or you can inline everything in a header file the way you're doing (but you really don't want to name these files with .cpp extensions, if they contain class declarations). Or you can just have one derived.h and throw away one.cpp and two.cpp altogether.
But you need to add the prerequisites in the makefile: if you keep multiple headers then main.o must depend on them.
Related
I'm trying to compile a C++ test file, which is supposed to compile from files that are in adjacent folders in the project file structure. I have the following:
Project/TestFiles/makefile
Project/TestFiles/test.cpp
Project/OtherFiles/my_stuff.cpp
Project/OtherFiles/my_stuff.hpp
For the compile, I'm trying to leave the my_stuff.o file in the OtherFiles folder, so if I have other makefiles, they dont have to recompile separate versions each.
My makefile looks as follows:
CC = g++
CFLAGS = -std=c++11 -Wall -Wcomment -Werror -Wextra -Weffc++ -pedantic
run: test.out
test.out: test.cpp catchMain.cpp ../OtherFiles/my_stuff.o
$(CC) $(CFLAGS) $^ -o $#
my_stuff.o: ../OtherFiles/my_stuff.cpp ../OtherFiles/my_stuff.hpp
$(CC) $(CFLAGS) -c $<
I thought for a while that this setup worked, but then I started getting some weird problems and couldn't compile. For instance, having a static const map produced error: expected ';' after top level declarator. At first, Internet seemed to indicate that Mac compilers sometimes aren't able to compile static const maps with member initialisation lists (which it also complained about, if I removed the static const part). However, when I commented out everything to do with the std::map (leaving the makefile as described above) OR placed all files in the same folder (rewriting both the makefile as well as the #includes in test.cpp), everything is ok, but I'd like to use both std::maps AND the chosen file structure. Oh, and removing the extra warning flags doesn't work either.
Any ideas how I could do that?
Edit
my_stuff.hpp:
namespace my_stuff {
void function();
}
my_stuff.cpp:
#include "my_stuff.hpp"
#include <map>
namespace my_stuff {
static const std::map<char, char> the_map {{'a', 'b'}, {'c', 'd'}};
void my_function() {
// map stuff
}
}
The test part is both a vanilla catchMain.cpp:
#define CATCH_CONFIG_MAIN
#include "../../Catch2/catch.hpp" //which is outside the project specifics
and the actual tests, my_tests.cpp:
#include "../../Catch2/catch.hpp"
#include "../OtherFiles/my_stuff.hpp"
#include <map>
SCENARIO("", "") {
GIVEN("") {
WHEN("") {
THEN("") {
my_function();
// Other stuff
}
}
}
}
As #S.M. pointed out, you must change the my_stuff.o rule, but you must change the recipe as well as the target, so that it will actually build the thing you want:
../OtherFiles/my_stuff.o: ../OtherFiles/my_stuff.cpp ../OtherFiles/my_stuff.hpp
$(CC) $(CFLAGS) -c $< -o $#
More generally, you must understand the language before you attempt to manipulate it. Swapping patches in and out to see what works is a very inefficient way to write code.
I am new to C++ and am trying to get the hang of build systems like make/CMake. Coming from Go, it seems that there is a constant risk that if you forget to do a little thing, your binaries will become stale. In particular, I can't find a best practice for remembering to keep dependencies/prerequisites updated in make/CMake. I'm hoping I am missing something obvious.
For example, suppose I have a basic makefile that just compiles main.cpp:
CFLAGS = -stdlib=libc++ -std=c++17
main: main.o
clang++ $(CFLAGS) main.o -o main
main.o: main.cpp
clang++ $(CFLAGS) -c main.cpp -o main.o
main.cpp:
#include <iostream>
int main() {
std::cout << "Hello, world\n";
}
So far so good; make works as expected. But suppose I have some other header-only library called cow.cpp:
#include <iostream>
namespace cow {
void moo() {
std::cout << "Moo!\n";
}
}
And I decide to call moo() from within main.cpp via `include "cow.cpp":
#include <iostream>
#include "cow.cpp"
int main() {
std::cout << "Hello, world\n";
cow::moo();
}
However, I forget to update the dependencies for main.o in makefile. This mistake is not revealed during the obvious testing period of running make and rerunning the binary ./main, because the whole cow.cpp library is directly included in main.cpp. So everything seems fine, and Moo! is printed out as expected.
But when I change cow.cpp to print Bark! instead of Moo!, then running make doesn't do anything and now my ./main binary is out of date, and Moo! is still printed from ./main.
I'm very curious to hear how experienced C++ devs avoid this problem with much more complicated codebases. Perhaps if you force yourself to split every file into a header and an implementation file, you'll at least be able to quickly correct all such errors? This doesn't seem bulletproof either; since header files sometimes contain some inline implementations.
My example uses make instead of CMake, but it looks like CMake has the same dependency listing problem in target_link_libraries (though transitivity helps a bit).
As a related question: it seems like the obvious solution is for the build system to just look at the source files and infer dependencies (it can just go one level in and rely on CMake to handle transitivity). Is there a reason this doesn't work? Is there a build system that actually does this, or should I write my own?
Thanks!
First of all you will need to reference the dependencies file in your Makefile.
This can be done with the function
SOURCES := $(wildcard *.cpp)
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
wich will take the name of all *.cpp files and substitute and append the extension *.d to name your dependency.
Then in your code
-include $(DEPENDS)
- tells the Makefile to not complain if the files do not exist. If they exist they will be included and recompile your sources properly according to the dependencies.
Finally the dependencies can be created automatically with the options: -MMD -MP for the rules to create the objects file. Here you can find a complete explanation. What generates the dependencies is MMD; MP is to avoid some errors. If you want to recompile when system libraries are updated use MD instead of MMD.
In your case you can try:
main.o: main.cpp
clang++ $(CFLAGS) -MMD -MP -c main.cpp -o main.o
If you have more files it is better to have a single rule to create object files. Something like:
%.o: %.cpp Makefile
clang++ $(CFLAGS) -MMD -MP -c $< -o $#
You can take a look also at this 2 great answers:
one
two
In your case a more suitable Makefile should look like the following (there might be some errors but let me know):
CXX = clang++
CXXFLAGS = -stdlib=libc++ -std=c++17
WARNING := -Wall -Wextra
PROJDIR := .
SOURCEDIR := $(PROJDIR)/
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR := $(PROJDIR)/
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
all: main
clean:
$(RM) $(OBJECTS) $(DEPENDS) main
# Linking the executable from the object files
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
#include your dependencies
-include $(DEPENDS)
#create OBJDIR if not existin (you should not need this)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile | $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
EDIT to answer comments
As another question, is there any problem with rewriting the DEPENDS definition as just DEPENDS := $(wildcard $(OBJDIR)/*.d)?
Nice question, it took me a while to see your point
From here
$(wildcard pattern…) This string, used anywhere in a makefile, is
replaced by a space-separated list of names of existing files that
match one of the given file name patterns. If no existing file name
matches a pattern, then that pattern is omitted from the output of the
wildcard function.
So wildcard return a list of the file names matching the pattern. patsubst acts on strings, it does not care about what are those strings: it is used as a way to create the file names of the dependencies, not the files themselves. In the Makefile example that I posted DEPENDS is actually use in two cases: when cleaning with make clean and with include so in this case they both work because you are not using DEPENDS in any rule. There are some differences (I tried to run and you should too to confirm). With DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES)) if you run make clean dependencies *.d that do not have a correspondent *.cpp file will not be removed while they will with your change. On the contrary you might include dependencies not relevant to your *.cpp file.
I asked this questions: let's see the answers.
If the .d files get deleted from carelessness but the .o files remain, then we are in trouble. In the original example, if main.d is deleted and then cow.cpp is subsequently changed, make won't realize it needs to recompile main.o and thus it will never recreate the dependency file. Is there a way to cheaply create the .d files without recompiling the object files? If so then we could probably recreate all the /.d files on every make command?
Nice question again.
Yes, you are right. Actually it was an error of mine. This happens because of the rule
main: main.o
$(CXX) $(WARNING) $(CFLAGS) main.o -o main
actually should have been:
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
so that it got relinked (the executable is updated) whenever one of the objects change and they will change whenever one their cpp file change.
One problem remains: if you delete your dependencies but not the objects, and change only one or more header files (but not the sources) then your program is not updated.
I corrected also the previous part of the answer.
EDIT 2
To create the dependencies you can also add a new rule to your Makefile:
here is an example.
So I have a straightforward problem.
I have files List.hpp, List.h, and test_list.cpp
List.hpp contains function definitions for the List.h file.
The List.h file includes "List.hpp" in the 3rd to last line.
test_list.cpp runs the program and includes "List.h" at the top.
I need a makefile that will compile these into an executable "project.x".
So far have this:
proj2: List.o test_list.o
gcc -o proj2.x List.o test_list.o
List.o:
gcc -c List.hpp
test_list.o:
gcc -c test_list.cpp
clean:
rm *.o proj2.x
However, it results in all kinds of errors, all dealing with lines that have List <T> in them, stating that List does not name a type. I think this is because I am not properly including the header file.
How would I make this makefile?
Judging by the filename extensions and your description, you're compiling C++ code.
You should thus use a C++ compiler: g++. gcc is a C compiler and doesn't know about C++.
You should really just let make compile your code for you, it knows what to do:
proj2: test_list.o
$(CXX) $(LDFLAGS) $(LDLIBS) -o $#
clean:
rm *.o proj2
You don't normally want to compile a header in isolation. It's intended to be included in a source file, and the source file is what you compile.
Given the implicit dependencies in a typical make utility, you can reduce your Makefile a little bit:
proj2.x: test_list.o
g++ -o proj2.x test_list.o
test_list.o: test_list.cpp List.hpp
clean:
-rm *.o proj2.x
At least assuming a reasonably recent version of Make, it'll already know how to compile a .cpp file to get a .o file.
If you're having compiler errors, chances are at least pretty fair that they stem from problems in the code, not in the Makefile. The obvious exceptions would be things like your C++ code failing to link properly, because you used gcc instead of g++ to link it.
As an aside, the header dependency shown in:
test_list.o: test_list.cpp List.hpp
...is something that gcc can generate automatically with the -MM flag. For a tiny Makefile like this one, it's probably not worthwhile to mess with generating dependencies automatically, but for a large one it can be worthwhile. You can even include this as a step in the Makefile itself by running gcc with -MM to generate the dependencies (directing the output to a file) and including that file into a Makefile that does the real work).
More about dependency generation and how to use it in a Makefile:
http://scottmcpeak.com/autodepend/autodepend.html
You don't compile .h or .hpp files. You only compile .c or .cpp files. You probably want something like(Indenting with tabs, not spaces, spaces is a SO and python thing, tabs are a makefile thing):
proj2: list.cpp list.hpp list.h
g++ -o proj2.x list.cpp
clean:
rm proj2.x
Also, in your C file, you will need:
#include "List.h" /* Note the quotes: *
#include <list.h> * won't work */
And likewise for your #include "List.hpp".
I have written the following makefile:
CC=g++
all: happy
happy: happy.o HappyLetter.o
$(CC) -o happy happy.o HappyLetter.o
happy.o: happy.cpp
$(CC) -c happy.cpp
HappyLetter.o: HappyLetter.cpp
$(CC) -c HappyLetter.cpp
clean:
rm -rf *.o happy
and am working with the files HappyLetter.cpp and happy.cpp (which includes the former) to create an executable named happy.
I can build the code successfully using make. However, when I modify HappyLetter.cpp and type 'make' again, the change is not reflected. It only works when I type 'make clean' and then 'make'. The update of the object file that I expect to take place is echoed to the command line:
$ make
g++ -c HappyLetter.cpp
g++ -o happy happy.o HappyLetter.o
However, the update to HappyLetter.cpp is not being reflected in happy.
The problem does not work in the other direction. That is, if I modify happy.cpp, the change is reflected immediately after I type 'make'.
I have replicated this problem with three make binaries on my Mac OS X, and also on an Ubuntu machine. So I must be doing something wrong in the coding. Here is the text of the files, which are in the same directory as the makefile:
happy.cpp
#include "HappyLetter.cpp"
int main()
{
printf("Hello from happy.cpp!\n");
HappyLetter *myObj = new HappyLetter();
myObj->speak();
return 0;
}
HappyLetter.cpp
#include <cstdio>
class HappyLetter {
public:
void speak()
{
printf("Hello from HappyLetter.cpp!\n");
}
};
I believe the problem is something simple, but I have no more ideas about what to check. One assumption I have is that the ordering of the rules and dependencies does not matter.
As I commented:
First, you should (conventionally) not #include "HappyLetter.cpp" in your happy.cpp (even if that is doable but poor taste). You should have a separate header file (with the conventional include guard)
#ifndef HAPPY_INCLUDED
//// file happy.h
#define HAPPY_INCLUDED
class HappyLetter {
public:
void speak();
};
#endif /*HAPPY_INCLUDED*/
(You may -or not- decide to e.g. #include <cstdio> in your happy.h before the class HappyLetter; there are good reasons to do both ways!)
Then you should have a first source file:
// file happy.cpp
#include <cstdio>
#include "happy.h"
int main() {
printf("Hello from happy.cpp!\n");
HappyLetter *myObj = new HappyLetter();
myObj->speak();
delete myObj;
return 0;
}
BTW, you should use smart pointers!
Then you have your second source file:
// file happyletter.cpp
#include <cstdio>
#include "happy.h"
void HappyLetter::speak() {
printf("Hello from HappyLetter.cpp!\n");
}
At last, a Makefile (see here for inspiration), like:
# file Makefile
CXX= g++
CXXFLAGS= -std=c++11 -Wall -Wextra -g
RM= rm -f
.PHONY: all clean
all: happy-prog
clean:
$(RM) *.o *~ happy-prog
happy-prog: happy.o happyletter.o
happy.o: happy.cpp happy.h
happyletter.o: happyletter.cpp happy.h
Notice the explicit dependency on happy.h header
As I commented, consider using remake-x or make --trace to debug your Makefile. Notice that GNU make has a lot of built-in rules, run make -p to get them.
Read more about C++11, notably a tutorial, a good programming in C++ book, have a glance into the standard (e.g. n3337 draft). Read also about make, notably GNU make.
Study the source code of some existing free software coded in C++ (see sourceforge or github etc... to find one).
(so you got both your C++ source files and your Makefile wrong!)
This is my first, attempt at a, Makefile after necessity from a previous post.
Anyway here's the code
SortLab.exe : SelectionSort.o Main.o
g++ -o $# $^
SelectionSort.o : SelectionSort.cpp SelectionSort.h
Main.o : Main.cpp
#-------------------------------------------------------------
run: SortLab.exe
./SortLab.exe
clean:
rm -f *.o
rm -f *.exe
build: clean SortLab.exe
%.o: %.cpp
g++ -c $<
I intend to have SelectionSort.cpp & SelectionSort.h form an object file, and Main.cpp to form its own object file. Then finally create an executable. Main.cpp depends on SelectionSort.cpp, where do I go wrong?
Also where can I find what the different GNU commands mean, -o -c and such
You shouldn't need to define the %.o: %.cpp rule yourself, Make knows how to compile C++.
Indent with tabs, not spaces; Make is sensitive to the difference.
Every object file should depend on the headers included in the source files it depends on. You probably need Main.o : Main.cpp SelectionSort.h.
build shouldn't depend on clean, it defeats one of Make's main features (selectively recompilation when files have changed).
If you make build the first target, you can run Make without a target to get a full compile. It's customary to call the main target all.