Why does make update precompiled headers sometimes, but not always? - c++

THE FILES
foo.hpp
#include <iostream>
class foo
{
public:
foo(int = 1);
int get_x() const { return x; }
private:
int x;
};
foo.cpp
#include "foo.hpp"
foo::foo(int xp)
{
x = xp;
}
main.cpp
#include "foo.hpp"
int main()
{
foo bar;
std::cout << bar.get_x() << std::endl;
}
Makefile (this is overkill for such a simple example, but I want to use something like this)
SHELL = /bin/bash
CC = g++
CPPFLAGS = -MMD -MP
SRC = $(wildcard *.cpp)
OBJ = $(SRC:.cpp=.o)
EXECUTABLE = main
all: $(SRC) $(EXECUTABLE)
$(EXECUTABLE): $(OBJ)
$(CC) $(OBJ) -o $#
.cpp.o:
$(CC) $(CPPFLAGS) -c $^
-include $(SRC:.cpp=.d)
OBSERVED BEHAVIOR
The files are 20K. Run make, output is 1 and files are 48K. Now change default argument int = 1 in header file to int = 2.
make: output is 2 and files are 11M. Nearly all of that is in foo.hpp.gch. Change int = 2 to int = 3.
make: output is still 2, foo.hpp.gch did not update.
Now if I move #include <iostream> out of foo.hpp and into main.cpp:
Files are 20K. Run make, output is 1 and files are 48K. Change int = 1 to int = 2.
make: output is 2 and files are 1.9M, nearly all of that in foo.hpp.gch. Change int = 2 to int = 3.
make: output is 3, foo.hpp.gch did update.
QUESTIONS
Why does make update a precompiled header (.gch) in one case, but not in the other? Why are the file sizes so different? What happened to the content of iostream? And how can I force make to always take into account changes in header files? I tried adding -fsyntax-only to CPPFLAGS, per this answer, but that gave an error.

To partially answer my own question, in the Makefile I changed $^ to -o $# $< and that seems to fix everything. The header files now update every time, and the combined files are only 144K. I got this idea here.

Related

How to create Makefile for multiple files in multiple directories?

Good morning,
I new in c++ and I am trying to compile my simple code to executable form. I will explain structure of project.
- main.cpp
- /utility/server.h
- /utility/server.cpp
I enclose file sources for complete information.
main.cpp
#include <iostream>
#include "utility/server.h"
using namespace std;
using namespace server;
int main() {
std::cout << "Content-type:text/html\r\n\r\n";
std::cout << "Your server name is: " << server::get_domain() << '\n';
return 0;
}
server.cpp
#include <cstdlib>
#include "server.h"
namespace server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
}
To my Makefile I added comments to understand what I want to do.
#
# 'make' build executable file
# 'make clean' removes all .o and executable files
#
# define the C compiler to use
CC = g++
# define any compile-time flags
CFLAGS = -Wall -g
# define any directories containing header files other than /usr/include
INCLUDES = -I../utility
# define the C++ source files
SRCS = main.cpp utility/server.cpp
# define the C++ object files
OBJS = $(SRCS:.cpp=.o)
# define the executable file
MAIN = executable.cgi
#
# The following part of the makefile is generic
#
.PHONY: depend clean
all: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS)
# this is a suffix replacement rule for building .o's from .cpp's
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -cpp $< -o $#
clean:
$(RM) *.o *~ $(MAIN)
depend: $(SRCS)
makedepend $(INCLUDES) $^
And finally error from compilation
g++ -Wall -g -I../utility -o executable.cgi main.o utility/server.o
Undefined symbols for architecture x86_64:
"server::get_domain()", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [executable.cgi] Error 1
From error message I understood there is problem with utility folder, but I don't know how to fix it.
Thank you for your help :)
In server.cpp, here:
namespace server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
}
You have made char* server::get_domain() a static function, making
its definition visible only within this translation unit and invisible to
the linker. Remove the keyword static here, and also in server.h if you have declared the function static there.
A namespace is not a class or struct. Confusingly,
namespace server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
}
server::get_domain() is a static function in that namespace. But
struct server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
};
it is a global function in that class, which the linker can see.

C++ How would I combine two makefile object target rules (which are located in another folder) into one target/rule?

My C++ program consists of three files:
two source files 'main.cpp' and 'hellolib.cpp'
a header file 'hellolib.h'
I am creating a makefile for this program. For my assignment I need one target ('hello') that compiles all source files in an executable.
Another target ('obj') should compile all '.cpp' files into objects and link them together in an executable.
When running make I prefer the object files to be created in a seperate folder called 'bin'. The source files are would be in a folder called 'src'. These folders are siblings, the makefile is in it's parent folder.
My makefile works fine but I wish two combine the two targets 'bin/main.o' and 'bin/hellolib.o' into one to reduce the amount of rules, especially for later when I am dealing with more source files.
I imagined the replacement would look something like this, but it doesn't seem to work.
It gives me the error: "*** No rule ot make target 'bin/main.o',
needed by 'obj'. Stop.
bin/%.o : src/%.cpp
$(CC) -c $< -o $#
Working Makefile:
CC = g++
SOURCES = ./src/main.cpp \
./src/hellolib.cpp
OBJECTS = ./bin/main.o \
./bin/hellolib.o
hello : $(SOURCES)
$(CC) -o $# $^
obj : $(OBJECTS)
$(CC) -o $# $^
bin/main.o : src/main.cpp
$(CC) -c $< -o $#
bin/hellolib.o : src/hellolib.cpp
$(CC) -c $< -o $#
clean:
#rm -rf hello obj bin/*.o
main.cpp:
#include "hellolib.h"
int main() {
Hello h("Name");
h.Print();
return 0;
}
hellolib.cpp
#include "hellolib.h"
#include <iostream>
Hello::Hello(std::string name) {
if (name.empty()) {
cout << "Name is not valid!";
return;
}
_name = name;
}
void Hello::Print() {
cout << "Hello " << _name << endl;
}
hellolib.h
#ifndef HELLO_LIB_H
#define HELLO_LIB_H
#include <string>
using namespace std;
class Hello {
std::string _name;
public:
Hello(std::string name);
void Print();
};
#endif
You need to change:
OBJECTS = ./bin/main.o \
./bin/hellolib.o
to:
OBJECTS = bin/main.o \
bin/hellolib.o
(Removing leading "./"). Either that, or change your pattern rule to include the leading "./":
./bin/%.o : src/%.cpp
$(CC) -c $< -o $#
Make rule matching uses text matching. It's not based on filenames, so "./././foo" and "foo" are not the same thing.
Personally I recommend rewriting like this:
SOURCES = src/main.cpp \
src/hellolib.cpp
OBJECTS = $(patsubst src/%.cpp,bin/%.o,$(SOURCES))
so you only need to keep the list of files in one place.
You can make a rule that builds anything conforming to a specific pattern like this:
bin/%.o : src/%.cpp
$(CC) -c -o $# $<
That will compile any bin/%.o dependency from the corresponding source src/%.cpp.
Also it is standard when compiling C++ to use CXX rather than CC (which is for C code).

Undefined Reference when Compiling to Executable

When I try to compile all of my object files into an executable, I get the error
lab5.o:lab5.cpp: undefined reference to 'Card::suitMap'
I assume it's an issue with correctly linking dependencies, but I don't really know how to verify whether I'm on the right track.
Here's the source file containing the main function:
#include "Card.h"
#include "Deck.h"
#include <iostream>
using namespace std;
int main()
{
Deck* deck1 = new Deck();
Deck* deck2 = new Deck();
for(int i = 0; i < deck1->deck.size(); i++)
{
Card card = deck1->draw();
cout << card.getSuit() << " " << card.getValue() << endl;
}
deck2->shuffle();
for(int i = 0; i < deck2->deck.size(); i++)
{
Card card = deck2->draw();
cout << card.getSuit() << " " << card.getValue() << endl;
}
}
Here's my Card.h which contains suitMap
#ifndef CARD_H
#define CARD_H
#include <string>
#include <map>
class Card {
private:
int value;
int suit;
public:
std::map <int, std::string> suitMap;
Card(int value, int suit);
int getValue() { return this->value; }
std::string getSuit() { return this->suitMap.find(this->suit)->second; }
};
#endif
I'm not sure if my makefile could contain the problem, but here it is as well
CC=g++
CFLAGS=-c -Wall -g -std=c++11
LDFLAGS=
SOURCES=lab5.cpp Card.cpp Deck.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=lab5
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -f *.o $(EXECUTABLE)
You must have had suitMap previously denoted static, and somehow not obtained a clean build after changing that. Be sure to perform a full clean build after modifying headers.
Your problem is due to a flaw in the makefile. A correctly designed makefile automatically manages all dependencies and thereby eliminates the need for running make clean to fix a build.
Below is an example makefile that would have prevented your problem. Rather than doing incremental builds, it always recompiles every source file. As you create larger projects, this approach may eventually become too slow, in which case you will want to invest in a more sophisticated build management solution. For your existing project, with this makefile, builds will likely take around one second on a modern PC.
EXECUTABLE = lab5
SOURCES += lab5.cpp Card.cpp Deck.cpp
CXXFLAGS += -Wall -Werror
CXXFLAGS += -std=c++11
CXXFLAGS += -g
.PHONY: build
build:
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(SOURCES) $(LDLIBS) -o $(EXECUTABLE)
.PHONY: clean
clean:
rm -f $(EXECUTABLE)

Linking in mac os x (10.8)

I'm trying to compile a multi file bit of code which up until now has been working fine.
But now I am getting some linker errors. I have a class definition 'njPhaseSpace' which is reported as being:
ld: duplicate symbol njPhaseSpace::njPhaseSpace(int)in Source/Currents.o and
/var/folders/p8/0bwv51kn2w5cx4jnsg6xm7340000gn/T//ccb0Psoz.o for architecture x86_64
I have no idea what the /var/folder/.../ccb0Psoz.o file is about and it isnt (intentionally) begin used in my project.
if I change the name to something different - but similar - such as njPhaseSpaceX it will compile and link up fine. But then I clean the project using 'make clean' and when I try to remake I get the same link error again! (but with a different /var/.../XXXXXX.o file)
Any suggestions?
Cheers
UPDATE: More strange things: When I look in the /var/folder/... directory to see which file is causing the duplication no such file exists!
UPDATE: The njPhaseSpace source file is:
// Standard header files
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <stdio.h>
#include <math.h>
#include <complex>
#include <iomanip>
#include "LoadBar.h"
// CLHEP header files
#include <CLHEP/Vector/LorentzVector.h>
#include <CLHEP/Random/RanluxEngine.h>
// More convenient label for four-vectors
typedef CLHEP::HepLorentzVector HLV;
// Definition of structure to hold the phase-space point
struct ParticleStruct {
HLV pa;
HLV pb;
HLV pep;
HLV pem;
HLV p1;
HLV p2;
HLV p3;
double xa;
double xb;
} ;
// A class for the n-jet phase space
class njPhaseSpace {
private:
// Incoming Particle Momenta
HLV pa;
HLV pb;
// Emitted leptons
HLV pep;
HLV pem;
// Outgoing parton momenta
std::vector <HLV> OutgoingPartons;
// Kinematic factors
double xa;
double xb;
public:
// Constructor for class
njPhaseSpace(int n);
// Returns a vector of the outgoing parton momenta
std::vector <HLV> ReturnOutgoingPartons() {
return OutgoingPartons;
}
// HLV IncomingForward
} ;
// Class constructor - adds n vectors to the Outgoing array
njPhaseSpace::njPhaseSpace(int n) {
// Add n final states to the OutgoingPartons vector
for (int i = 0; i < n; i++) {
HLV temp;
OutgoingPartons.push_back(temp);
}
}
UPDATE: This problem goes away when the class constructor is included in the body of the class definition. Whilst its good I can avoid this it doesnt really help because now to develop my class everything will have to sit inside the definition.
UPDATE: The makefile used to compile (Analysis is something seperate I am currently running make Explorer -j8):
#/bin/bash
# CXX Compiler
CXX = g++
# Directories For Compilation
INCDIR = MadGraph
LIBDIR = MadGraph
SRCDIR = Source
# Compilation Flags
CXXFLAGS = -O3 -lm
LIBFLAGS = $(shell clhep-config --libs) $(shell fastjet-config --libs) $(shell clhep-config --libs) $(shell root-config --libs)
INCFLAGS = $(shell clhep-config --include) -I/$(INCDIR) -I$(SRCDIR) -I. $(shell fastjet-config --cxxflags --plugins) $(shell clhep-config --libs) $(shell root-config --cflags)
FLAGS = $(CXXFLAGS) $(LIBFLAGS) $(INCFLAGS)
# Object Files
Objects = $(addprefix $(SRCDIR)/, Currents.o mstwpdf.o LoadBar.o)
MadObjects = $(addprefix $(LIBDIR)/, HelAmps_sm.o Parameters_sm.o read_slha.o CPPProcess2j.o CPPProcess3j.o)
# Main targets
all: Analysis Explorer
Analysis: $(SRCDIR)/Analysis2jepem.cxx $(Objects) $(SRCDIR)/CGenerator2jepem.o
$(CXX) $(SRCDIR)/Analysis2jepem.cxx -o $# $(FLAGS) $(Objects) $(SRCDIR)/CGenerator2jepem.o
Explorer: $(SRCDIR)/qQepemqQ_Explorer.cxx $(Objects) $(MadObjects) $(LIBDIR)/libmodel_sm.a
$(CXX) $(SRCDIR)/qQepemqQ_Explorer.cxx -o $# $(FLAGS) $(Objects) -lmodel_sm -L$(LIBDIR)
# Build object files
$(Objects):
$(CXX) -c $(#:.o=.cxx) -o $#
# Build the MG5 object code
$(MadObjects):
$(CXX) -c $(#:.o=.cxx) -o $# -I../
$(SRCDIR)/CGenerator2jepem.o:
$(CXX) -c $(#:.o=.cxx) -o $#
# Build the Standard Model library
$(LIBDIR)/libmodel_sm.a: $(MadObjects)
$(AR) cru $# $^
ranlib $#
# Debugging flags
debug: CXX += -g -Wall -pendantic
debug: all
# Create a clean build
.PHONY: clean
clean:
rm -f $(Objects) $(MadObjects) $(LIBDIR)/2j/libmodel_sm.a $(LIBDIR)/3j/libmodel_sm.a $(TARGET) $(SRCDIR)/CGenerator2jepem.o Analysis Explorer
The problem is that the class constructor is defined in the header file as:
njPhaseSpace::njPhaseSpace(int n) {
// Add n final states to the OutgoingPartons vector
for (int i = 0; i < n; i++) {
HLV temp;
OutgoingPartons.push_back(temp);
}
Either put it in the class declaration, or into it's own separate .cpp file that is compiled and linked separately.
This is no different from creating a non-inline/non-static/non anonymous namespaced function in a .h file and #including it in multiple .cpp files.
This error is sometimes prompted if you include the files like this:
File a included in file b;
Filb and file a included in file c.
Can you try to put the "static" keyword in front of the class constructor that gives you problems?

Replacing symbol from object file at compile time. For example swapping out main

Here's the use case:
I have a .cpp file which has functions implemented in it. For sake of example say it has the following:
[main.cpp]
#include <iostream>
int foo(int);
int foo(int a) {
return a * a;
}
int main() {
for (int i = 0; i < 5; i += 1) {
std::cout << foo(i) << std::endl;
}
return 0;
}
I want to perform some amount of automated testing on the function foo in this file but would need to replace out the main() function to do my testing. Preferably I'd like to have a separate file like this that I could link in over top of that one:
[mymain.cpp]
#include <iostream>
#include <cassert>
extern int foo(int);
int main() {
assert(foo(1) == 1);
assert(foo(2) == 4);
assert(foo(0) == 0);
assert(foo(-2) == 4);
return 0;
}
I'd like (if at all possible) to avoid changing the original .cpp file in order to do this -- though this would be my approach if this is not possible:
do a replace for "(\s)main\s*\(" ==> "\1__oldmain\("
compile as usual.
The environment I am targeting is a linux environment with g++.
I hate answering my own question, but here's a solution I ended up finding deep in the man page of g++, I've tested it and it works to what I would want it to...
g++ has the -D flag which allows you to define macros when compiling object files. I know you are thinking "ugh macros" but hear me out... You can use the macro definition to effectively rename a symbol. In my case, I can run the following command to generate an object file of my students code without their main file: g++ -D main=__students_main__ main.cpp -c -o main.nomain.o.
This creates an object file with their int main defined as int __students_main__. Now this isn't necessarily callable directly as they could have defined main as int main(void) or with the various combinations of argc and argv, but it allows me to effectively compile out their function.
The final compile looks like this:
g++ -c -D main=__students_main__ main.cpp -o main.nomain.o
g++ -c mymain.cpp -o mymain.o
g++ main.nomain.o mymain.o -o mymainstudentsfoo.out
For my purposes, I wanted to create a Makefile that would accomplish this automagically (ish) and I feel that is relevant to this discussion so I'll post what I came up with:
HDIR=./ # Not relevant to question, but we have headers in a separate directory
CC=g++
CFLAGS=-I $(HDIR)
NOMAIN=-D main=__student_main__ # The main renaming magic
.SECONDARY: # I forget exactly what this does, I seem to remember it is a hack to prevent deletion of .o files
cpp = $(wildcard *.cpp)
obj = $(patsubst %.cpp,%.o,$(cpp))
objnomain = $(patsubst %.cpp,%.nomain.o,$(cpp))
all: $(obj) $(objnomain)
clean:
rm -f *.o *.out
%.nomain.o: %.cpp
$(CC) $(CFLAGS) $(NOMAIN) -c $^ -o $#
%.o: %.cpp
$(CC) $(CFLAGS) -c $^
You can use the --allow-multiple-definition option of ld*:
[a.c]
#include <stdio.h>
int foo() { return 3; }
int bar() { return 4; }
int main(void)
{
printf("foo: %i\n", foo());
return 0;
}
[b.c]
#include <stdio.h>
int bar();
int main(void)
{
printf("bar: %i\n", bar());
return 0;
}
[shell]
$ gcc -Wall -c a.c
$ gcc -Wall -c b.c
$ gcc -Wl,--allow-multiple-definition a.o b.o -o foobar && foobar
foo: 3
$ gcc -Wl,--allow-multiple-definition b.o a.o -o foobar && foobar
bar: 4
*: At your own risk :)
I support 'djechlin's suggestion.
But if you want something quick and dirty, here's a suggestion:
You can define a macro and wrap your function calls like this,
#ifdef MYTESTING
#define ASSERTEQUAL(fn, parm, ret) \
assert( fn ( parm ) == ret )
#else
#define ASSERTEQUAL(fn, parm, ret) fn ( parm )
#endif
And in your main function use the following call,
ASSERTEQUAL( foo, i, 4);
Use the following compilation flag to enable the customized macro behavior.
-DMYTESTING
Hope this helps!
It is not possible to do this at compile time. You need a link time solution. (Or to make use of the preprocessor.)
In either case, you'd probably want to separate the "regular" and "testing" symbols and selectively include their source files in compilation, or object files in linking.*
Though I'd rather use a unit testing framework or at least NDEBUG for assert()s.
*e.g.:
#ifdef TESTING
#include "main-testing.c"
#else
#include "main.c"
#endif
or
ifdef TESTING
OBJS += main-testing.o
else
OBJS += main.o
endif
Update: I just realized that you're specifically looking for a solution where main-testing.o's main would override main.o's (right?). I'll keep this answer and add another one for the "override" solution.