Linkage error using shared dll with minimal C++/SWIG/Lua code - c++

This is a really specific compilation problem involving C++, SWIG and Lua.
I have a really simple base code :
[AClass.hpp]
class AClass {
public:
AClass();
};
[AClass.cpp]
#include "AClass.hpp"
AClass::AClass() {}
[main.cpp]
#include "AClass.hpp"
int main() {
AClass my_a;
}
At this point, there is no matter with compilation.
I first compile the class in libengine.dll and then use the shared library to build the executable.
Let's introduce a SWIG module, and add it to the dll :
[AClass.i]
%module M_AClass
%{
#include "AClass.hpp"
%}
%include "AClass.hpp"
Henceforth, when linking everything in an executable, I got the following error :
g++ -c main.cpp
g++ -c AClass.cpp
swig.exe -c++ -lua AClass.i
g++ -Iinclude -c AClass_wrap.cxx
g++ AClass.o AClass_wrap.o -shared -o libengine.dll -Wl,--out-implib,libengine.dll.a -L. -llua5.1
Creating library file: libengine.dll.a
g++ main.o libengine.dll.a -o main.exe
main.o:main.cpp:(.text+0x16): undefined reference to `AClass::AClass()'
collect2: ld returned 1 exit status
Would anyone have a clue ? I tried looking into the dll with nm but I can't figure how adding another .o to the shared library can "hide" a method (this isn't specific to constructors).
To reproduce the context, here are the necessary files to put in a directory to build the test :
include/ # Contains "lauxlib.h", "lua.h" & "luaconf.h"
liblua5.1.dll
AClass.hpp
AClass.cpp
AClass.i
main.cpp
Makefile
And finally, here is the Makefile content :
ifneq (,$(findstring Linux,$(shell uname -o)))
EXEC := main
LIB := libengine.so
LIB_FLAGS := -o $(LIB)
else
EXEC := main.exe
LIB := libengine.dll.a
LIB_FLAGS := -o libengine.dll -Wl,--out-implib,$(LIB)
#NO DIFFERENCE using ".dll.a" as in CMake (option: -Wl,--out-implib,) or only ".dll"
ifdef SystemRoot
# Pure Windows, no Cygwin
RM := del /Q
endif
endif
LANG_LIB := -L. -llua5.1
LANG_INC := include
LANG_SWIG := -lua
all: clean $(EXEC)
clean:
$(RM) main *.exe *_wrap.cxx *.o libengine.*
$(EXEC): main.o $(LIB)
g++ $^ -o $#
main.o: main.cpp
g++ -c $<
#NO PB without dependency to AClass_wrap.o
$(LIB): AClass.o AClass_wrap.o
g++ $^ -shared $(LANG_LIB) $(LIB_FLAGS)
AClass.o: AClass.cpp
g++ -fPIC -c $<
AClass_wrap.o: AClass_wrap.cxx
g++ -fPIC -I$(LANG_INC) -c $<
AClass_wrap.cxx: AClass.i
swig -c++ $(LANG_SWIG) $<
This was tested under Windows Seven, with MingGW g++ v4.5.2, SWIG 2.0.2 and Lua5.1.
EDIT: The problem also appear when SWIG-exporting to tcl. However, there is absolutely no problem compiling under Linux. I compared the generated AClass_wrap.cxx, they are similar.

g++ under mingw might require __declspec(dllimport/export)

Related

Add source file to Eclipse Makefile C++ project

I have created simple C++ Makefile Eclipse project in Ubuntu. Eclipse has created default Makefile:
PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
OBJS = cpp_makefile.o
ifeq ($(BUILD_MODE),debug)
CFLAGS += -g
else ifeq ($(BUILD_MODE),run)
CFLAGS += -O2
else ifeq ($(BUILD_MODE),linuxtools)
CFLAGS += -g -pg -fprofile-arcs -ftest-coverage
LDFLAGS += -pg -fprofile-arcs -ftest-coverage
else
$(error Build mode $(BUILD_MODE) not supported by this Makefile)
endif
all: cpp_makefile
cpp_makefile: $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
%.o: $(PROJECT_ROOT)%.cpp
$(CXX) -c $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -o $# $<
%.o: $(PROJECT_ROOT)%.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $# $<
clean:
rm -fr cpp_makefile $(OBJS)
Everything goes fine in case I have only one source file. In case I create class TestMe with it's header and cpp file and add include header to main cpp file build fails. Looks like system can't find TestMe.cpp.
Error:
Building in: /home/a/cpp-workspace2/cpp_makefile/build/default
make -f ../../Makefile
g++ -c -O2 -o cpp_makefile.o /home/a/cpp-workspace2/cpp_makefile/cpp_makefile.cpp
g++ -o cpp_makefile cpp_makefile.o
/usr/bin/ld: cpp_makefile.o: in function `main':
cpp_makefile.cpp:(.text.startup+0x1c): undefined reference to `TestMe::TestMe()'
collect2: error: ld returned 1 exit status
make: *** [../../Makefile:19: cpp_makefile] Error 1
Build complete (3 errors, 0 warnings): /home/a/cpp-workspace2/cpp_makefile/build/default
In case I use same source in Eclipse C++ Managed build project everything goes fine. How to solve this problem in right way In Eclipse Makefile project?
cpp_makefile.cpp
#include "TestMe.h"
int main(int argc, char **argv)
{
TestMe testMe = TestMe();
return 0;
}
TestMe.h:
class TestMe {
public:
TestMe();
virtual ~TestMe(){};
};
TestMe.cpp:
#include "TestMe.h"
TestMe::TestMe() {
}
Eclipse will create a default Makefile for you, but it does not manage the Makefile(s) in a makefile-based project. It cannot really do so while also allowing you to make your own makefile changes or supporting makefiles it did not generate itself. If you want the build configuration to be completely managed by Eclipse then you should choose a different project type.
With a makefile-based project, then, you need to make appropriate changes to the Makefile yourself when you add sources to the project. In this particular case, it looks like you should change
OBJS = cpp_makefile.o
to
OBJS = cpp_makefile.o TestMe.o

Adding the -M flag to g++ causes a file format not recoginzed error

Adding the -m flag to g++ causes a file format not recognized; treating as linker script, which in turns causes a syntax error when linking.
I'm using this makefile:
# Compilers
CXX = g++
#CXX = clang++
CC = gcc
UNAME := $(shell uname)
# Directories used for input and output
SRCDIR = src/src
BUILDDIR = build
EXEDIR = bin
INCLUDEDIR = src/include
VERBOSE = 0
# Debug flags
ifeq ($(VERBOSE), 1)
CXX_FLAGS += -M
endif
# Enable all warnings but format and unused variables
CXX_FLAGS += -Wall -Wno-format -Wno-unused-variable -Wno-varargs -c -g -O0 -fbuiltin -fpermissive -std=c++14 -I include -I $(INCLUDEDIR)
OUTPUT_NAME = Test
# Where the sources are located
SRCS = $(wildcard $(SRCDIR)/*.cpp)
SRCS += $(wildcard $(SRCDIR)/*/*.cpp)
CSRCS = $(wildcard $(SRCDIR)/*.c)
# Where the compiled objects are located
OBJS = $(patsubst $(SRCDIR)/%.cpp, $(BUILDDIR)/%.o, $(SRCS))
COBJS = $(patsubst $(SRCDIR)/%.c, $(BUILDDIR)/%.o, $(CSRCS))
# Linking all the .o files and with the libs
build: $(OBJS) $(COBJS)
$(CXX) $^ $(LINKER_FLAGS) -o ./bin/$(OUTPUT_NAME)
# Compiling all the .cpp files into .o files
$(OBJS): $(BUILDDIR)/%.o : $(SRCDIR)/%.cpp
$(CXX) $(CXX_FLAGS) -o "$#" "$<"
$(COBJS): $(BUILDDIRT)/%.o : $(SRCDIR)/%.c
$(CC) $(CC_FLAGS) -o "$#" "$<"
# Running the created exe
.PHONY: run
run:
./$(EXEDIR)/$(OUTPUT_NAME)
In src/src I have two files, test.cpp and foo.cpp.
test.cpp:
#include "foo.h"
#include "cstdio"
int main(int argc, char* argv[]) {
Foo f;
int b = f.bar(2);
printf("%d", b);
return 0;
}
foo.cpp:
#include "foo.h"
Foo::Foo() {
}
Foo::~Foo() {
}
int Foo::bar(int c) {
return c + c;
}
The .h file for foo.cpp is in src/include:
foo.h:
#ifndef _FOO_H
#define _FOO_H
class Foo {
public:
Foo();
~Foo();
int bar(int c);
};
#endif
Calling make build compiles the code fine, and I get the output I expect, 4. But by calling make VERBOSE=1 build (which turns on the -M flag for g++) I get
/usr/bin/ls:build/foo.o: file format not recognized; treating as linker script
usr/bin/ld:build/foo.o:1: syntax error
I'm confused as to why enabling the -M flag would cause this, because I thought that -M output the dependencies of the program. If someone could point me in the correct direction I would really appreciate it.
The -M flag makes the compiler output dependencies to wherever it would otherwise have put its object file, as Barry explained in his answer. It does not print the dependencies on screen. Additionally, it disables C/C++ compilation altogether -- only preprocessing is performed.
If you were using the -M option to generate dependency files as input for make, you could use the -MD option to make the compiler output dependencies to a .d file alongside the object file. (In your case, for instance, that would make it generate a foo.d file along with the object file foo.o.)
Since it sounds like you just want to print the dependencies to the screen, though, you can use the -MF option to redirect the dependency output, e.g.
-M -MF /dev/stdout
Well, of course! You're right that -M changes the output of gcc from an object file to a rules file that make can import. But then you're using those result files not as dependency files to be -included into your makefile, but as object files!
In short, you're doing something like this:
g++ -c foo.cxx -o foo.o
g++ -c bar.cxx -o bar.o
g++ -o exe foo.o bar.o
which works. And then changing it to:
g++ -M -c foo.cxx -o foo.o
g++ -M -c bar.cxx -o bar.o
g++ -o exe foo.o bar.o
You're naming the results of those operations foo.o and bar.o, but they're not object files, and when you try to link them together, the linker will fail because... they're not object files. This should be extremely clear if you try to cat your "verbose" build object files and see what they actually look like.

Undefined reference to function when using shared library in Linux

I have some problems to use a custom shared library, since I get undefined reference errors for some functions from two of many other source files.
If I compile the whole project with main file (release:), everything works just fine. But if I create a shared library (lib:) and use this library with the main file (all:), those compile time errors occur.
Here is a snippet of my makefile
release:
$(CC) -Wall -s -w $(INCLUDES) $(LIBRARY) $(SRC) mainfile.cpp $(OCV) $(BOOST) $(GLOG) $(GFLAGS) -o test.exe
lib:
$(CC) -fPIC $(INCLUDES) $(LIBRARY) -c $(SRC) $(OCV) $(BOOST) $(GLOG) $(GFLAGS)
mv *.o obj/
$(CC) -shared -o libOutput.so obj/*.o
all:
$(CC) -Wall -s -w $(INCLUDES) $(LIBRARY) mainfile.cpp -L/path/to/lib/ -lOutput $(OCV) $(BOOST) $(GLOG) $(GFLAGS) -o project.exe
Since there is no error during compilation using the release-option, I'm assuming that there is a linker specific problem.
I inspected the specific object files using GNU Binary Utilities
nm -C obj/specific.o | grep functionName
with no results. I did the same for the shared library, but this time with the following result,
U functionName(std::vector<int>)
which means that the function is unknown.
Do you have any suggestions, how to fix this issue?

Trouble compiling/linking C and C++ files

I have tried searching around other questions here on SO, but have still been unable to get my newly created C++ and .h linked to my main C file correctly. My implementation of my loader.cpp and loader.h are based off of this SO question.
My loader.cpp has no main function as I just want to use the C++ functions there. My shift.c file is where my int main() is located. Here is the basic structure of my loader.cpp file.
loader.cpp
#include "loader.h"
...
// Class Declaration
...
// Class implementation
I have been trying to compile with the following.
g++ loader.cpp -o obj -lGLU -lGL -lglut
The error I am getting here is...
(.text+0x20): undefined reference `to main'
So my two questions are, how do I get my cpp file to compile properly, and then what do I need to add to my Makefile to link them properly?
Makefile (for reference)
CC = gcc
CXX = g++
EXE = shift gears
# Main target
all: $(EXE)
CFLG=-O3 -Wall
LIBS=-lglut -lGLU -lGL -lm
CLEAN=rm -f $(EXE) *.o *.a
# Dependencies
gears.o: gears.c
shift.o: shift.c CSCIx229.h
fatal.o: fatal.c CSCIx229.h
loadtexbmp.o: loadtexbmp.c CSCIx229.h
print.o: print.c CSCIx229.h
project.o: project.c CSCIx229.h
errcheck.o: errcheck.c CSCIx229.h
object.o: object.c CSCIx229.h
# Create archive
CSCIx229.a:fatal.o loadtexbmp.o print.o project.o errcheck.o object.o
ar -rcs $# $^
# Compile rules
.c.o:
gcc -c $(CFLG) $<
.cpp.o:
g++ -c $(CFLG) $<
# Link
shift:shift.o CSCIx229.a
gcc -O3 -o $# $^ $(LIBS)
gears:gears.o
gcc -O3 -o $# $^ $(LIBS)
# Clean
clean:
$(CLEAN)
If you want g++ to compile an object module without linking it into a complete program then you must give it the -c option:
g++ -c loader.cpp -o loader.o
Note that that compilation command also assigns a conventional name to the generated object file, and that if you're not linking it into an executable then you don't need to specify libraries to link it to. Your Makefile is already set up for this.
If you add loader.o to the dependencies of CSCIx229.a then that should be enough to persuade make to build it from loader.cpp and to include the object file in your library (which will make it available for linking into your executables). You may also need to add some or all of -lGLU -lGL -lglut to your LIBS variable. It might also be appropriate to add loader.o's dependencies to the makefile if they include more than just loader.cpp itself (e.g. if they include CSCIx229.h).
Add the -c option to compile only. When you are ready to link the final application, then include all the object files and the list of libraries.
g++ -c loader.cpp -o loader.o
g++ loader.o (and the rest of your object files) -lGLU -lGL -lglut
Try adding this to your makefile:
shift:shift.o CSCIx229.a loader.o
gcc -O3 -o $# $^ $(LIBS)

C/C++ project compiles with Xcode but not with gcc/g++

When compiling a little C or C++ project in terminal using gcc, g++ or make, I get these kind of errors:
/tmp/ccG1caGi.o: In function `main':
main.c:(.text+0xa): undefined reference to `display_menu'
main.c:(.text+0xf): undefined reference to `get_input'
collect2: ld returned 1 exit status
main.c:
#include "menu.h"
int main()
{
display_menu();
get_input();
return 0;
}
menu.h:
void display_menu();
int get_input();
However with Xcode I get no errors or warnings.
What could be the issue here? It's seems it's like this when I include files.
So, gcc is complaining that it doesn't know where display_menu and get_input are, what they are doing or how to link them in, and rightly so.
You probably have more sourcefiles, where those functions are defined (menu.c, perhaps?). If so, add them to your compile instruction:
gcc main.c menu.c
Alternatively, just compile into an object (waiting for the functions later) with the -c flag. This will not make an executable, but will make an object file that awaits final compilation with
gcc main.c -c # Make the main.o object
gcc menu.c main.o # Link the main.o object with a compiled menu.c
into a final executable.
Xcode, in all likelihood, knows all about all your source files, and is happy to put them all together in its compilation step. If you are doing it manually, you have to do a little more work yourself. Its not when you include files (h files, that is) but when you have multi-file sources.
Try with a basic Makefile:
CC=gcc
CFLAGS=-W -Wall
LDFLAGS=
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
all: myexec
myexec: $(OBJ)
#$(CC) -o $# $^ $(LDFLAGS)
%.o: %.c
#$(CC) -o $# -c $< $(CFLAGS)
.PHONY: clean
clean:
#rm -rf *.o