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.
Related
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.
I'm trying to compile C++ 11 code on a server running Ubuntu from my home computer using Putty. I'm using a makefile to compile and include shared pointers in the code, but it gives me this error:
/usr/include/c++/4.8/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
However, when I try to compile the code from the server hosting the files (when I'm at university), it compiles perfectly. Here is my makefile:
all: huffmandriver.o huffmannode.o huffmantree.o
g++ -o huffencode huffmandriver.o huffmannode.o huffmantree.o -std=c++11
huffmannode.o: huffmannode.cpp huffmannode.h
g++ -c huffmannode.cpp -std=c++11
huffmantree.o: huffmantree.cpp huffmantree.h
g++ -c huffmantree.cpp -std=c++11
clean:
#rm -f *.o
#rm -f huffencode
I have also tried adding the flags -stdlib=libc++ -std=gnu++, but that does not work either. Here is a snippet of the code where the error is being thrown:
// Huffman Node class header
#ifndef HUFFMANNODE_H
#define HUFFMANNODE_H
#include <memory>
#include <string>
namespace YNGMAT005 {
class HuffmanNode {
private:
std::shared_ptr<HuffmanNode> left;
std::shared_ptr<HuffmanNode> right;
std::shared_ptr<HuffmanNode> parent;
std::string letter;
int frequency;
public:
HuffmanNode(std::string l, int freq);
~HuffmanNode();
std::shared_ptr<HuffmanNode> & get_left();
std::shared_ptr<HuffmanNode> & get_right();
std::shared_ptr<HuffmanNode> & get_parent();
void set_left(std::shared_ptr<HuffmanNode> & l);
void set_right(std::shared_ptr<HuffmanNode> & r);
bool has_left();
bool has_right();
void set_parent(std::shared_ptr<HuffmanNode> & p);
bool has_parent();
std::string get_letter();
int get_frequency();
};
}
#endif
Many thanks!
I don't know why you're seeing different behaviour from a different login context (check which g++; g++ --version on both and see if your .profile, .bash_profile or .bashrc does anything weird based on ssh-vs-local login).
Nonetheless, you should be able to getting it working in both settings by providing -std=c++11 to the default rule for .cpp to .o thus:
CXXFLAGS = -std=c++11
Additionally, (shamelessly stealing from Daniel's answer) you can remove the explicit rules for the other .cpp files, just leaving the .h dependencies:
huffmannode.o: huffmannode.h
huffmantree.o: huffmantree.h
These will then automatically pick up the CXXFLAGS setting.
You might need to compile huffmandriver.cpp with -std=c++11 as well. Currently, you have rules for compiling huffmannode.cpp and huffmantree.cpp with the -std=c++11 compiler option, but not huffmandriver.cpp.
You can create a custom pattern rule for making .o files from .cpp files and specifying the header dependencies like so:
huffmannode.o: huffmannode.h
huffmantree.o: huffmantree.h
%.o: %.cpp
g++ -std=c++11 -c -march=native -o $# $<
An alternative approach is to define the CXXFLAGS implicit variable to -std=c++11. This way, the built-in rule ā$(CXX) $(CPPFLAGS) $(CXXFLAGS) -cā for compiling C++ source files will use the -std=c++11 compiler option.
I've been given a package of files (one .cpp, and some .c and .h) and want to make some modifications. But right now I'm just trying to get the original version to compile (in Linux).
Here's a (really) minimal working example:
mainfile.cpp
extern "C"{
#include "auxfile.h"
}
int main(int argc, char * argv[]){
getfoo(temperature);
return 0;}
auxfile.h
#define PUBLIC
#define PRIVATE static
extern int temperature;
int getfoo( int inputint);
auxfile.c
#include "auxfile.h"
int temperature = 37;
PUBLIC int getfoo( int inputint){
return 7;
}
When I type
g++ mainfile.cpp
I get
mainfile.cpp(.text+0x11): undefined reference to `temperature'
mainfile.cpp(.text+0x18): undefined reference to `getfoo'
collect2: ld returned 1 exit status
For what it's worth, I've looked through numerous "undefined reference" questions and spent dozens of hours working on my own. The above code presents the essence of the problem. Any help would be massively appreciated. Thanks.
At the time of linking, all symbols (except those for dynamic linking, aka shared libraries) have to be defined. To create an object file with possibly unresolved symbols for later linking, there is the -c flag, that means just compile, do not link.
So, the following would work:
g++ -c -omainfile.o mainfile.cpp
gcc -c -oauxfile.o auxfile.c
g++ -o mainfile mainfile.o auxfile.o
Only the last line actually invokes the linker and as you have both object files, all symbols are found.
Just for completeness, in a real-world scenario you'd handle compiling and linking using make. Create a Makefile with the following contents:
OBJS:= mainfile.o auxfile.o
all: mainfile
# $# means what to build (in this case "mainfile"), $^ is replaced by all
# dependencies (here the contents of the variable OBJS)
mainfile: $(OBJS)
g++ -o$# $^
# pattern for *.cpp -> create a *.o file with same name using g++
%.o: %.cpp
g++ -c -o$# $<
# the same for *.c, but using gcc here
%.o: %.c
gcc -c -o$# $<
clean:
rm -f $(OBJS)
# "PHONY" are targets, that are not actually the names of output files
.PHONY: all clean
Then just type make and see the "magic" happening. Of course this is just for starters, no dependencies are tracked etc...
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!)
I wanted to use the unordered_map STL in c++, but as soon as I use the header, it gives me this error:
This file requires support for the compiler and library support for the ISO C++11 standard. This support is currently experimental and must be enabled with -std=c++11 or -std=gnu++11 compiler options.
I am attaching my code that I wanted to run, below. (Any inputs on the code are welcome too. thanks)
#include <iostream>
#include <unordered_map>
using namespace std;
class Node
{
public:
string a,b;
Node()
{
a="hello";
b="world";
}
};
int main ()
{
unordered_map<Node> mymap;
Node mynode;
mymap.insert(mynode);
std::cout << "myrecipe contains:" << std::endl;
for (auto& x: mymap)
std::cout << x.a << ": " << x.b << std::endl;
}
Edit: I got it to work by using the following commmand: g++ -std=c++11 [filename].cpp
Thanks for the help.
The main answer to your question: specify -std=c++11 in your compile command.
Precisely which C++11 features are available will depend on your version of GCC. Here are two links that might help:
https://gcc.gnu.org/projects/cxx0x.html
http://wiki.apache.org/stdcxx/C++0xCompilerSupport
First Option:
You can remove to error with -std=c++11 in compile time.
g++ -o binary yourFile.cpp -std=c++11
Second Option to integrate the development with c++11:
You can use a makefile with the CXXFLAGS set with -std=c++11 A makefile is a simple text file with instructions about how to compile your program. Create a new file named Makefile (with a capital M). To automatically compile your code just type the make command in a terminal. You may have to install make.
Here is the code :
CXX=clang++
CXXFLAGS=-g -std=c++11 -Wall -pedantic
BIN=prog
SRC=$(wildcard *.cpp)
OBJ=$(SRC:%.cpp=%.o)
all: $(OBJ)
$(CXX) -o $(BIN) $^
%.o: %.c
$(CXX) $# -c $<
clean:
rm -f *.o
rm $(BIN)
It assumes that all the .cpp files are in the same directory as the makefile. But you can easily tweak your makefile to support a src, include and build directories.
compile with:
g++ -o binary source.cpp -std=c++11