To make this short, I have a CPP and C code, and my CPP code is trying to reference functions from the C code with a header file. Whenever I run the make command, I end up getting "undefined reference" errors. Here are my codes:
cpp_code.cpp:
extern "C"{
#include "header_code.h";
}
int main(){
cout << "Hello" << endl;
return 0;
}
c_code.c:
#include "header_code.h"
int main(){
printf("Hello");
return 0;
}
void initalize(){
printf("Initilized");
}
header_code.h:
extern void initalize();
makefile:
CXX = g++
CXXFLAGS = -std=c++11
CC = gcc
DEPS = header_code.h
CFLAGS = -I
OBJS = cpp_code.o c_code.o
c: $(OBJS)
$(CXX) -o $# $^ $(CXXFLAGS)
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $<
%.o : %.c $(DEPS)
$(CC) -c $(CFLAGS) $<
Whenever running make it always gives me problems. Can anyone please help me? Thank you for your time reading all of this!
[basic.start.main]
A program that declares a variable main at global scope, or that declares a function main at global scope attached to a named module, or that declares the name main with C language linkage (in any namespace) is ill-formed.
So, as a C++ program, it's ill-formed. Remove the C main function.
Other problems:
In the makefile you have
CFLAGS = -I
and whatever comes after that when compiling will be treated as a directory to search for header files in. In your makefile, that's the source file. Correction:
CFLAGS =
or
CFLAGS = -I.
Your header file is missing a header guard and header files that are supposed to be used by both C and C++ code usually contain the extern "C" part themselves to not burden C++ users to add it.
cpp_code.cpp
#include "header_code.h"
#include <iostream>
int main() {
initalize(); // call the C function
std::cout << "Hello" << std::endl;
}
c_code.c
#include "header_code.h"
#include <stdio.h>
void initalize(){
printf("Initilized");
}
header_code.h
#ifndef HEADER_CODE_H_
#define HEADER_CODE_H_
#ifdef __cplusplus
extern "C" {
#endif
extern void initalize();
#ifdef __cplusplus
}
#endif
#endif
makefile
CXX = g++
CXXFLAGS = -std=c++11
CC = gcc
DEPS = header_code.h
CFLAGS = -I.
OBJS = cpp_code.o c_code.o
c: $(OBJS)
$(CXX) -o $# $^ $(CXXFLAGS)
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $<
%.o : %.c $(DEPS)
$(CC) -c $(CFLAGS) $<
Related
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).
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()'
I read different answers about VLA on SO but couldn't find the answer. In my case, I have one function that allocates memory:
template<typename T>
void allocMemory(T *&data, const size_t numElems)
{
#ifdef PINNED_MEMORY
// allocate pinned memory
#else
data = new T[numElems];
#endif
}
Now, I have a vector class where I use this method:
template<typename T>
class MyVec
{
T *data;
size_t size;
public:
MyVec(size_t _size): size(_size)
{ allocMemory<T>(data, size); } // gives VLA warning
};
It happens when I compile it using nvcc (V0.2.1221) compiler which I guess uses gcc compiler underneath (?) The actual warning is:
myvec.h:16:6: warning: ISO C++ does not support variable-length array types [-Wvla]
data = new T[numElems];
I think you don't compile your project the right way.
Try to using the flowing make file.
CUDA_INSTALL_PATH := /usr/local/cuda
CXX := g++
CC := gcc
LINK := g++ -fPIC
NVCC := nvcc
#Includes
INCLUDES = -I. -I$(CUDA_INSTALL_PATH)/include
#Common flags
COMMONFLAGS += $(INCLUDES)
NVCCFLAGS += $(COMMONFLAGS)
CXXFLAGS += $(COMMONFLAGS)
CFLAGS += $(COMMONFLAGS)
LIB_CUDA := -L$(CUDA_INSTALL_PATH)/lib -lcudart
#OBJS = GpuSolver.cu.o main.cpp.o
OBJS = main.cu.o a.cpp.o # your files
TARGET = a.out
LINKLINE = $(LINK) -o $(TARGET) $(OBJS) $(LIB_CUDA)
.SUFFIXES: .c .cpp .cu .o
%.c.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
.cu.o: %.cu
$(NVCC) $(NVCCFLAGS) -c $< -o $#
%.cpp.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
$(TARGET): $(OBJS) "makefile" #your makefile file name
$(LINKLINE)
I have a static method in class as follows in file Convert.h
class Convert
{
public :
static string convertIntToStr(unsigned int integer);
};
In Convert.cpp
string
Convert::convertIntToStr(unsigned int integer)
{
ostringstream ostr;
ostr << integer;
return ostr.str();
}
I use this in some other class method in another .cpp file as Convert::convertIntToStr, but I get linking error, which says undefined reference to Convert::convertIntToStr(unsigned int). Could you please let me know what could be wrong?
With multiple cpp file, you have to link the compiled object file into executable. In IDE like eclipse CDT or Visual stdio, It has been done for you.
To compile and link by yourself, with gcc for example, write Makefile:
CC=g++
CPPFLAGS=-fPIC -Wall -g -O2
all:executable
executable: convert.o other.o
$(CC) $(CPPFLAGS) -o $# $^
convert.o: convert.cpp
$(RC) $^
other.o: other.cpp
$(CC) -o $# -c $^
.PHONY:clean
clean:
rm *.o executable
I am wondering if it's possible to display full file path using the assert macro?
I cannot specify full file path in compilation command, is there still a way to do it?
My debug environment is linux/g++
You can add the following macro option into your compilation line (Can be easily modify for your environment)
%.o: %.cpp
$(CC) $(CFLAGS) -D__ABSFILE__='"$(realpath $<)"' -c $< -o $#
then you just have to this to have your full path:
#include <stdio.h>
int main()
{
printf(__ABSFILE__);
// will be expanded as: printf("/tmp/foo.c")
}
EDIT
Even better than this: The following rules is enough !!!
%.o: %.cpp
$(CC) $(CFLAGS) -c $(realpath $<) -o $#
And you can now use __FILE__ macro:
#include <stdio.h>
int main()
{
printf(__FILE__);
// will be expanded as: printf("/tmp/foo.c")
}
assert uses the __FILE__ macro to get the filename. It will expand to the path used during compilation. For example, using this program:
#include <stdio.h>
int main(void)
{
printf("%s\n", __FILE__);
return 0;
}
If I compile with 'gcc -o foo foo.c' and run, I'll get this output:
foo.c
But if I compile with 'gcc -o foo /tmp/foo.c' and run, I'll get this output instead:
/tmp/foo.c