lib.h:
#include <iostream>
namespace lib {
template <class T>
void f(T t)
{
std::cout << "lib f " << t << std::endl;
}
}
client.cpp:
#include "lib.h"
// explicit instantiation
template
void lib::f(char);
int main()
{
lib::f('x');
}
libmock.h:
#include <iostream>
#include "lib.h"
namespace lib {
template <>
void f(char c)
{
std::cout << "libmock f " << c << std::endl;
}
}
Makefile:
run: prod test
./prod
./test
prod: client.o
${CXX} -o $# $^
test: client.o libmock.o
${CXX} -o $# $^
clean:
-rm *.o prod test
Using GCC 4.3.2 (and also "IBM XL C/C++ for AIX, V11.1 (5724-X13)"), I get the results that I expect:
$ make
g++ -c -o client.o client.cpp
g++ -o prod client.o
g++ -c -o libmock.o libmock.cpp
g++ -o test client.o libmock.o
./prod
lib f x
./test
libmock f x
That is, I've injected new functionality into the client by linking it with an object that provides a more-specialized function template than the one offered by the library.
However, if I use "CC: Sun C++ 5.12 SunOS_sparc Patch 148506-14 2013/09/24", then I get this error:
$ CXX=CC make
CC -c -o client.o client.cpp
CC -o prod client.o
CC -c -o libmock.o libmock.cpp
CC -o test client.o libmock.o
ld: fatal: symbol 'void lib::f<char>(__type_0)' is multiply-defined:
(file client.o type=FUNC; file libmock.o type=FUNC);
Makefile:9: recipe for target 'test' failed
make: *** [test] Error 2
My solution must work with all three of these compilers. Am I just getting lucky with some undefined behavior in GCC and AIX? Are there some options I could pass to the Sun compiler to get this to work? Does what I'm trying to do show that I'm not fully understanding these template concepts? Enlighten me, please!
Your test binary that links libmock.o and client.o together violates the one definition rule (in the client translation unit it uses the default version and in the libmock translation unit it uses the specialized version) and thus both linker behaviors are ok.
I will continue thinking about alternatives but right now the only solutiion I can think of is to conditionally include libmock.h in client.cpp based on whether you're doing the mock test build or not.
Related
I created my Makefile for a simple program but it returns undefined reference for class functions constantly:
g++ -c src/main.cpp -o lib/main.o
g++ -c src/functions.cpp -o lib/functions.o
g++ -c src/Circular.cpp -o lib/Circular.o
g++ lib/main.o -o bin/app.exe
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: lib/main.o:main.cpp:(.text+0x20): undefined reference to `Circular::Circular()'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [app.exe] Error 1
Here is my Makefile:
app.exe: lib/main.o lib/Circular.o lib/functions.o
g++ lib/main.o -o bin/app.exe
lib/functions.o: src/functions.cpp
g++ -c src/functions.cpp -o lib/functions.o
lib/Circular.o: src/Circular.cpp
g++ -c src/Circular.cpp -o lib/Circular.o
lib/main.o: src/main.cpp
g++ -c src/main.cpp -o lib/main.o
Here is a short snippet of main.cpp:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>
#include "../include/Circular.h"
#include "../include/functions.h"
using namespace std;
int main(int argc, const char * argv[]) {
Circular item;
return 0;
}
Circular.h:
#include "node.h"
class Circular
{
public:
Circular();
node *start;
node *last;
int counter;
}
Circular.cpp:
#include "../include/Circular.h"
#include <iostream>
using namespace std;
Circular::Circular()
{
start = NULL;
last = NULL;
}
and node.h:
struct node
{
int data;
struct node *next;
struct node *prev;
};
I know the problem is about linker and with Makefile but even though I tried different possible solutions, somehow it doesn't work. Therefore, maybe someone can see the mistake I am making. Thanks!
I managed to create a Makefile from this source .
The Makefile looks like this:
CXX = g++
CXXFLAGS = -std=c++17 -Wall
LXXFLAGS = -std=c++17
OBJECTS = main.o Circular.o functions.o
TARGET = main
$(TARGET): $(OBJECTS)
$(CXX) $(LXXFLAG) $(OBJECTS) -o $(TARGET)
main.o: main.cpp Circular.cpp Circular.h functions.cpp functions.h
$(CXX) $(CXXFLAGS) -c main.cpp
Circular.o: Circular.cpp
$(CXX) $(CXXFLAGS) -c Circular.cpp
functions.o: functions.cpp
$(CXX) $(CXXFLAGS) -c functions.cpp
clean:
rm -f $(TARGET) $(OBJECTS)
And also added cout to you Circular constructor to check the execution as below:
#include "Circular.h"
#include <iostream>
using namespace std;
Circular::Circular()
{
start = NULL;
last = NULL;
cout << "Yes!" << endl;
}
Here's the result:
Output
Don't forget to put a semicolon for your Circular class in your Circular.h.
NOTE: If you aren't able to use make in cmd,use choco install make.
The Makefile should be structured to build the dependencies, then the final assembly into a .exe. Each path should be specified exactly as it is, not approximated:
app.exe: lib/main.o lib/Circular.o lib/functions.o
g++ lib/main.o lib/Circular.o lib/functions.o -o app.exe
lib/main.o: src/main.cpp
g++ -c src/main.cpp -o lib/main.o
lib/functions.o: src/functions.cpp
g++ -c src/functions.cpp -o lib/functions.o
lib/Circular.o: src/Circular.cpp
g++ -c src/Circular.cpp -o lib/Circular.o
The key here is be consistent and that includes things like the order of things specified in this file. Whatever order you pick, stick to it. This makes tracking down problems way easier.
If this project gets more complex you probably want to pivot to using a dependency tracking Makefile template instead of this homebrew one. Note how in those you don't need to specify a rule for each file, but instead a rule for each type of file, as in .cpp -> .o, and the rest happens automatically.
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.
I write simple testing program in C++, which will tell Hello, Alex and exit.
Here it's code:
main.cpp:
#include <iostream>
#include <dlfcn.h>
int main()
{
void* descriptor = dlopen("dll.so", RTLD_LAZY);
std::string (*fun)(const std::string name) = (std::string (*)(const std::string)) dlsym(descriptor, "sayHello");
std::cout << fun("Alex") << std::endl;
dlclose(descriptor);
return 0;
}
dll.h:
#ifndef UNTITLED_DLL_H
#define UNTITLED_DLL_H
#include <string>
std::string sayHello(const std::string name);
#endif
dll.cpp:
#include "dll.h"
std::string sayHello(const std::string name)
{
return ("Hello, " + name);
}
makefile:
build_all : main dll.so
main : main.cpp
$(CXX) -c main.cpp
$(CXX) -o main main.o -ldl
dll.so : dll.h dll.cpp
$(CXX) -c dll.cpp
$(CXX) -shared -o dll dll.o
But when I build my code with make, I have such error:
/usr/bin/ld: dll.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
dll.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
makefile:8: recipe for target 'dll.so' failed
make: *** [dll.so] Error 1
What did I make not correct?
P.S. I use GNU Make 3.81 on Ubuntu Server 14.04.3 with GNU GCC 4.8.4
Update
If I link dll.so file with -fPIC param, I have the same error
Firstly, a bit off topic, but in your makefile, it would be better to specify build_all as a phony target
.PHONY: build_all
Next, you are compiling dll.cpp without relocatable code. You need to add -fpic or -fPIC (see here for an explanation of the difference).
$(CXX) -c dll.cpp -fpic
Lastly, unix doesn't automatically add file suffixes, so here you need to specify .so:
$(CXX) -shared -o dll.so dll.o
I did a sample project in linux but i am getting error while running main Makefile
Project Info:
project/database folder having files database.h , database.cpp , bulid-database ,Makefile
database.h
/*data base file*/
#include<iostream>
using namespace std;
class mydatabase
{
public:
mydatabase(int a , int b);
int sum(){return m_a +m_b;}
int diff(){return m_a -m_b;}
int mul(){return m_a *m_b;}
float div(){return m_a /m_b;}
int reminder(){return m_a %m_b;}
private:
int m_a , m_b;
};
database.cpp
#include "database.h"
mydatabase::mydatabase(int a ,int b):m_a(a) , m_b(b)
{
}
bulid-database
make
if [ -f libdatabase.a ];
then
echo "Database-Library Build Success"
cp libdatabase.a ../LIBs/
else
echo "databse-Library Build Failure"
fi
Makefile
HEADERFILES = $(wildcard *.h)
CPPFILES = $(wildcard *.cpp)
OBJFILES = $(patsubst %.cpp,%.o ,$(wildcard *.cpp))
$(OBJFILES): %.o : %.cpp $(HEADERFILES)
g++ -c -o $# $<
ar ruv libdatabase.a $#
ranlib libdatabase.a
project/Main folder having files main.cpp , Makefile
main.cpp
#include "database.h"
#include <iostream>
int main()
{
mydatabase *obj = new mydatabase(10 ,5);
std::cout<<"sum is"<<obj->sum()<<endl;
std::cout<<"diff is"<<obj->diff()<<endl;
std::cout<<"mul is"<<obj->mul()<<endl;
std::cout<<"div is"<<obj->div()<<endl;
std::cout<<"reminder is"<<obj->reminder()<<endl;
getchar();
return 0;
}
Makefile
CC = g++
INCPATH = -I. \
-I.. \
-I../database
LIBPATH = -L../LIBs
LDFLAGS = ${LIBPATH}/libdatabase.a
CFLAGS = ${INCPATH}
testdate:main.o
$(CC) $(CFLAGS) -o testdate main.o $(LDFLAGS)
main.o:main.cpp
$(CC) $(CFLAGS) -c -o main.o main.cpp
ISSUE: database make file is working fine but main Makefile i am having some issue like
Error: main.o: In function main':
main.cpp:(.text+0x92): undefined reference tomydatabase::mydatabase(int, int)'
collect2: ld returned 1 exit status
This line is wrong:
$(CC) $(CFLAGS) -o testdate $(LDFLAGS) main.o
because the library should be specificed AFTER the object main.o on the line. This is due to the way the linker handles the objects. Look at this example:
gcc -o test someobject.o library.a
The linker will:
look up all undefined references of someobject.o and store them
then it opens library.a and resolves the undefined references via library.a
then it closes library.a
If the object and the library are in the other way around, then the linker opens library.a, sees no undefined references in its table and closes it. Then it tries and compiles someobject.o and the undefined references are never satisfied
EDIT:
This is a well-known caveat of GCC, a more detailed stack-overflow explanation can be seen here, and options --start-group and --end-group can help resolve cases where A depends on B, and B depends on A.
It's your Makefile. You want:
libdatabase.a
or
-ldatabase
at the end of your main compile line
I have a project using functions from a class CRandomMersenne, declared in header randomc.h; the functions are defined in a different file mersenne.cpp. In my makefile I have an object *MC_funcs2.o* that uses functions from the class. The source *MC_funcs2.cpp* includes the header randomc.h. However the compiler complains:
MC_funcs2.o:MC_funcs2.cpp:(.text+0x20): undefined reference to `CRandomMersenne::Random()'
I understand there is something I've done wrong with declaring functions outside the class definition, including header file to use mentioned functions and maybe with the linking in the makefile. Here is a stripped down version of some of the files:
makefile:
SpMC3: SpMC3.cpp SpMC.h mersenne.o MC_funcs2.o
g++ SpMC3.cpp MC_funcs2.o mersenne.o -o SpMC3
MC_funcs2.o: MC_funcs2.cpp SpMC.h randomc.h
g++ -c MC_funcs2.cpp mersenne.cpp
mersenne.o: mersenne.cpp randomc.h userintf.cpp
g++ -c mersenne.cpp userintf.cpp
SpMC3.cpp (main program):
#include "SpMC.h"
int main() {
cout << "boing" << endl;
return 0;
}
MCfuncs2.cpp (the one that doesn't compile):
#include "SpMC.h"
#include "randomc.h"
CRandomMersenne RanGen(time(0));
void outrandom() {
ofstream out;
out << RanGen.Random() << endl;
return;
}
Any ideas?
This error just means mersenne.cpp not being compiled ...make sure it get compiled and linked...
I would strongly advise compiling each individual source file *.c to a object file *.o, i.ex. mersenne.cpp -> mersenne.o. This can be achieved without having to specify each object file manually.
CC = gcc
CFLAGS = -g -O2
OBJECTS = main.o foo.o
main : $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o main
%.o : %.c
$(CC) $(CFLAGS) -c $<
For further information on makefiles, please take a look a this tutorial or excellent SO answer in How to make a SIMPLE C++ Makefile?.