I am learning programming under Linux, and I faced the following problem during linking.
My directory structure
libraries
|-- archive_sample
| |-- calc.h
| |-- calc.cpp
| |-- makefile
|
|-- test_archive
|-- main.cpp
|-- makefile
calc.h
#ifndef __CALC__H__
#define __CALC__H__
int add(int a, int b);
int sub(int a, int b);
#endif
calc.cpp
#include "calc.h"
int add(int a, int b)
{
return (a + b);
}
int sub(int a, int b)
{
return (a - b);
}
File archive_sample/makefile:
libcalc.a : calc.o
ar rcs libcalc.a calc.o
calc.o : calc.cpp calc.h
g++ $(CFLAGS) -c calc.cpp
clean :
rm -f libcalc.a calc.o
When I run "make" from archive_sample directory, it executes successfully and calc.o and libcalc.a are created in the same directory.
main.cpp
int main()
{
int a, b;
std::cin >> a >> b;
std::cout << "a + b : " << add(a, b) << std::endl;
std::cout << "a - b : " << sub(a, b) << std::endl;
return (0);
}
Compiling with
g++ -c -I../archive_sample main.cpp
succeeds and main.o is created. However linking with
g++ -L../archive_sample -lcalc main.o -o test
gives the following error:
main.o: In function main:
main.cpp:(.text+0x3e): undefined reference to add(int, int)
main.cpp:(.text+0x84): undefined reference to sub(int, int)
collect2: error: ld returned 1 exit status
Where am I going wrong?
Also "make" is also not working for the following makefile.
test_archive/makefile
test : main.o
g++ -L../archive_sample -lcalc main.o
main.o : main.cpp calc.h
g++ $(CFLAGS) -c -I../archive_sample main.cpp
clean :
rm -f test *.o
with error
make: *** No rule to make target `calc.h', needed by `main.o'. Stop.
How can I fix this problem?
For the first error, since main.cpp and archive_sample are in the same directory, you shouldn't specify -Larchive_sample rather than -L../archive_sample.
For the second error, your calc.h is in the archive_sample directory, so the dependency should be listed as archive_sample/calc.h.
Related
I need to declare a very large n-d array. It is defined in a header file and never changes. Unfortunately compiling the main file takes a very long time, so I decided to bring it out into it's own object file.
Here is the header file tables.hpp:
#pragma once
namespace TABLES
{
extern const int A[10][10][10];
extern const int B[10][10][10];
}
Here is the source file tables.cpp:
namespace TABLES
{
const int A[10][10][10] = {}; // use default for brevity
const int B[10][10][10] = {}; // use default for brevity
}
and my main file:
#include "tables.hpp"
int main()
{
printf("%d", TABLES::A[0][0][0]);
}
and here is my Makefile:
CXX = clang++
CFLAGS = -std=c++17 -g -flto -Wall -Iinclude/
SRC = src/
INC = include/
tables.o: $(SRC)tables.cpp $(INC)tables.hpp
$(CXX) $(CFLAGS) -c $(SRC)tables.cpp
main: main.cpp tables.o
$(CXX) $(CFLAGS) -o main main.cpp tables.o
the tables.o compiles successfully, however I am having issues linking the tables.o to the main program:
undefined reference to `TABLES::A'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Makefile:30: recipe for target 'main' failed
make: *** [refactor] Error 1
My project contains a sub.h file that I was instructed to only have the following contents:
int sub(int n, int *A, int *B, int *C);
sub.h performs an unspecified action on 3 arrays taken from an input.txt file.
The instructions say that the sub.o will be provided later when the project is submitted. My question is, how do I create a makefile for a given .o file that I cannot access yet? It is difficult for me to tell whether or not my makefile will be successful since I do not have the sub.o.
The project only contains main.cpp, sub.h, and the makefile.
Here's what I have for the makefile so far:
project: main.o sub.o
g++ main.o message.o -o project
main.o: main.cpp sub.h
g++ -c -g main.cpp
clean:
rm main.o sub.o project
One solution is to have a sub.cpp that provides some implementation of sub() and make your Makefile build the sub.o.
When you submit the project, put the provided sub.o where it is supposed to be generated. In such case, the "real" sub.o will be used to compile your binary.
You can't compile to an executable (i.e. link) if you have a missing object file. But you can (only) compile main.c to an object file - at this stage it doesn't matter that sub is undefined. I can only assume that the linking happens when you submit.
This main.c will compile to an object:
int sub(int n, int *A, int *B, int *C);
int main()
{
int n = 0;
int* A = 0;
int* B = 0;
int* C = 0;
sub(n, A, B, C);
}
using e.g.
gcc -c main.cpp
and if you do get hold of sub.o you can link using
gcc main.o sub.o -o project
I got 'undefined reference' when compile code with a static library. I have searched a lot of answer which told to use extern "C" or correct the order of parameter when compiling, but those doesn't solve my problem.
I have these :
compiler.hpp
#ifndef COMPILER_H
#define COMPILER_H
int buildTree();
#endif
compile.cpp
#include <compiler.hpp>
int buildTree() {
Package package = new Package();
}
And a lot of another source code, then I build them to lib.a by building them into .o files with -c flag and :
ar rvs lib.a $(OBJS)
My Main.cpp:
#include <compiler.hpp>
int main() {
buildTree();
}
Finally, I build executable file :
LIBS = lib.a
main: main.cpp
$(CPP) $(CPPFLAGS) $(LIBDIR) $^ $(LIBS) -o $#
But g++ complier throws this Error :
undefined reference to `buildTree()'
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.
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