MinGW: building a dynamic library with opencv - c++

A want to build a simple dll, that shows an image:
#include <opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
void showimagedata(uchar * dataBuffer,int width,int height)
{
Mat image(Size(width, height), CV_8UC1, dataBuffer, Mat::AUTO_STEP);
imshow("image",image);
}
How can I compile it with MinGW?
I tried the following:
g++ -c -fPIC showimg.cpp -o showimg.o -I"C:\opencv\build-mingw\install\include" -L"C:\opencv\build-mingw\install\x86\mingw\lib" -lopencv_core247 -lopencv_highgui247
g++ -shared -Wl,-soname,libshowimg.so.1 -o libshowimg.so.1.0.1 showimg.o
but it seems that the linker cant find the symbols.
Filenames and paths are correct, but I'm not certain about the naming conventions.
The two libs are called: libopencv_core247.dll.a libopencv_highgui247.dll.a

Related

C++ Shared Lib: On Windows the client link's just fine but on Linux (GCC) gets undefined errors

Edited: ODR violation fixed.
Edited: I found that reordering the link directories (-L) fixed the problem but I don't know why.
The original order in the g++ command that was causing the problem was this:
-L/usr/local/lib
-L/usr/local/lib64
-L/usr/lib
-L/usr/lib/64
-L../../bin/Release
Moving -L../../bin/Release which contains the VampEngine.so fixed the problem, but why?
Edited Ends Here
I have two projects. VampEngine (A shared lib) and Application (the client). When I compile both of them on Windows (visual c++), VampEngine links just fine with the Application but on Linux I get undefined errors (g++).
I checked if the correct flags and paths are passed in the compiler's arguments and it seem right.
Also I'm pretty positive that I use extern "C" in both the dll implementation and in the client's decelerations.
Here is analytically the g++ makefile execution:
-------------- Clean: Debug|x64 in VampEngine (compiler: GNU GCC Compiler)---------------
Cleaned "VampEngine - Debug|x64"
-------------- Clean: Debug|x64 in Application (compiler: GNU GCC Compiler)---------------
Cleaned "Application - Debug|x64"
-------------- Build: Debug|x64 in VampEngine (compiler: GNU GCC Compiler)---------------
g++ -m64 -fPIC -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/VampEngine/src/core.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/core.o
g++ -m64 -fPIC -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/VampEngine/src/stb_image/stb_image.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/stb_image/stb_image.o
g++ -m64 -fPIC -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/VampEngine/src/window.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/window.o
g++ -shared -L/usr/lib -L/usr/lib64 -L/usr/local/lib -L/usr/local/lib64 ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/core.o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/stb_image/stb_image.o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/window.o -o ../../bin/Debug/libVampEngine.so -s -shared -m64 -L/usr/lib64 -lGL -lGLEW -lglfw
Output file is ../../bin/Debug/libVampEngine.so with size 138.57 KB
-------------- Build: Debug|x64 in Application (compiler: GNU GCC Compiler)---------------
g++ -m64 -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I../../VampEngine/src -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/Application/src/main.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o
g++ -L/usr/lib -L/usr/lib64 -L/usr/local/lib -L/usr/local/lib64 -L../../bin/Debug -o ../../bin/Debug/Application ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o -s -m64 -L/usr/lib64 -lVampEngine
/usr/bin/ld: ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o: in function `VampEngine::Core::Core(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned int, unsigned int)':
main.cpp:(.text._ZN10VampEngine4CoreC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEjj[_ZN10VampEngine4CoreC5ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEjj]+0x31): undefined reference to `Vamp_Core_Constructor'
/usr/bin/ld: ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o: in function `VampEngine::Core::~Core()':
main.cpp:(.text._ZN10VampEngine4CoreD2Ev[_ZN10VampEngine4CoreD5Ev]+0x17): undefined reference to `Vamp_Core_Deconstructor'
/usr/bin/ld: ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o: in function `VampEngine::Core::MainLoop()':
main.cpp:(.text._ZN10VampEngine4Core8MainLoopEv[_ZN10VampEngine4Core8MainLoopEv]+0x17): undefined reference to `Vamp_Core_MainLoop'
collect2: error: ld returned 1 exit status
Process terminated with status 1 (0 minute(s), 1 second(s))
4 error(s), 0 warning(s) (0 minute(s), 1 second(s))
Here is the core.cpp file which contains the implementation of the extern functions in the shared library:
#include "core.h"
#include "window.h"
#include <GLFW/glfw3.h>
#include "Engine/API.h"
namespace VampEngine
{
CoreImpl::CoreImpl(std::string title, unsigned int width, unsigned int height)
: window( new WindowImpl(title, width, height) )
{
}
CoreImpl::~CoreImpl()
{
delete window;
}
void CoreImpl::MainLoop()
{
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window->m_window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/* Swap front and back buffers */
glfwSwapBuffers(window->m_window);
/* Poll for and process events */
glfwPollEvents();
}
}
}
extern "C" VAMP_API void* Vamp_Core_Constructor(const char* title, unsigned int width, unsigned int height)
{
return new VampEngine::CoreImpl(title, width, height);
}
extern "C" VAMP_API void Vamp_Core_Deconstructor(void* obj)
{
VampEngine::CoreImpl *object = (VampEngine::CoreImpl*)obj;
delete object;
}
extern "C" VAMP_API void Vamp_Core_MainLoop(void* obj)
{
VampEngine::CoreImpl* object = (VampEngine::CoreImpl*)obj;
object->MainLoop();
}
And this is the core.hpp which the client includes and compiles in his main.cpp file:
#ifndef VAMP_ENGINE_CORE_HPP
#define VAMP_ENGINE_CORE_HPP
#include <Engine/API.h>
#include <iostream>
extern "C"
{
VAMP_API void* Vamp_Core_Constructor(const char* title, unsigned int width, unsigned int height);
VAMP_API void Vamp_Core_Deconstructor(void* obj);
VAMP_API void Vamp_Core_MainLoop(void* obj);
}
namespace VampEngine
{
class Core
{
private:
void* m_core;
public:
Core(std::string title, unsigned int width, unsigned int height)
: m_core(Vamp_Core_Constructor(title.c_str(), width, height))
{
}
~Core()
{
Vamp_Core_Deconstructor(m_core);
}
void MainLoop()
{
Vamp_Core_MainLoop(m_core);
}
};
}
#endif
The VAMP_API macro is empty when compiled on Linux.
#ifndef VAMP_ENGINE_API_H
#define VAMP_ENGINE_API_H
//On Windows Platforms.
#ifdef VAMP_PLATFORM_WINDOWS
#ifdef VAMP_BUILD_DLL
#define VAMP_API _declspec(dllexport)
#else
#define VAMP_API _declspec(dllimport)
#endif
//Unix-Based Systems (GCC).
#else
#define VAMP_API
#endif
#endif
As you can see I use exactly the same names.
So what else can cause an undefined error?
I use arch linux x64, with gcc version:
$gcc --version
gcc (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Problem solved.
My code was just fine, the culprit was actually another libVampEngine.so library that was copied in /usr/lib by me. The linker was searching in the /usr/lib directory first and then the bin/ directory of my project, so instead of using the right .so file to link against, it was using the outdated one.
If anyone else is experiencing a problem like this and is almost certain that his code is fine, follow these steps:
1) Ensure that the linker is actually linking the correct shared library.
2) Check the library directories (-L) that the linker is searching for binaries.
-Make sure these directories do not contain a binary with the exact same name as
your own library.
3) Be carefull of outdated binary files. If the linker is linking against
one but your code has been updated, even if the program links correctly you will get
undefined behavior on runtime.

C++, can't access included header files from so library

I try to include my self built .so library in the test.cpp file.
When I try to make the test.cpp file I get this exception:
root#airdrop:/home/pi/naza-interface/examples# make
g++ -c test.cpp
test.cpp:31:35: fatal error: naza_interface_manual.h: No such file or
directory
#include "naza_interface_manual.h"
^
compilation terminated.
Makefile:5: recipe for target 'test.o' failed
make: *** [test.o] Error 1
The Makefile for test.cpp looks like that:
output: test.o
g++ -L. -lnazainterface -o test test.o
test.o:
g++ -c test.cpp
clean:
rm -f *.o
test.cpp just includes the library.
#include "naza_interface_manual.h"
The library contains two files, naza_interface_manual.h and naza_interface_manual.cpp. The library's makefile looks like that:
libso: naza_interface_manual.o pca9685.o
g++ -fPIC -L/usr/local/lib -shared naza_interface_manual.o
pca9685.o -lbcm2835 -o libnazainterface.so
naza_interface_manual.o: src/naza_interface_manual.cpp src/naza_interface_manual.h
g++ -fPIC -c -Wall src/naza_interface_manual.cpp
pca9685.o: src/PCA9685/pca9685.cpp src/PCA9685/pca9685.h
g++ -c src/PCA9685/pca9685.cpp
install: naza_interface_manual.o pca9685.o
g++ -L/usr/local/lib naza_interface_manual.o pca9685.o -lbcm2835 -
shared -o /usr/local/libnazainterface.so
clean:
rm *.o output
naza_interface_manual.h:
#ifndef NAZA_INTERFACE_MANUAL_H_
#define NAZA_INTERFACE_MANUAL_H_
class naza_interface_manual_c{
public:
naza_interface_manual_c();
// A: For roll control (left/right)
// E: For pitch control (front/back)
// T: For throttle control
// R: For rudder control
// U: For Control Model Switch
void configure_pins(int A, int E, int T, int R, int U);
void fly_forward(int speed);
void fly_backward(int speed);
void fly_up(int speed);
void fly_down(int speed);
void fly_left(int speed);
void fly_right(int speed);
};
#endif
naza_interface_manual.cpp:
#include <iostream>
#include <wiringPi.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "naza_interface_manual.h"
#include "PCA9685/pca9685.h"
naza_interface_manual_c::naza_interface_manual_c(){
std::cout << "Starting Naza Interface";
}
void naza_interface_manual_c::configure_pins(int A, int E, int T, int R, int U){
PCA9685 pca9685;
pca9685.SetFrequency(100);
pca9685.Write(CHANNEL(0), VALUE(350));
}
void naza_interface_manual_c::fly_forward(int speed){
}
void naza_interface_manual_c::fly_backward(int speed){
}
void naza_interface_manual_c::fly_up(int speed){
}
void naza_interface_manual_c::fly_down(int speed){
}
void naza_interface_manual_c::fly_left(int speed){
}
void naza_interface_manual_c::fly_right(int speed){
}
Your Makefile doesn't install the header file. In fact, it also installs the shared object in a non-standard location: /usr/local. You want the library to go into /usr/local/lib and you need the header file installed in /usr/local/include.
Your Makefile is not consistent with conventional rules: You have no all rule, you are creating the library directly in the installation directory, instead of calling /usr/bin/install... I suggest you look into "proper" Makefile layout, if you want to distribute this. Users expect a lot of things from the Makefiles you give them; there are de-facto standards to follow.
If you want to use the library without having installed it, you need to provide the compiler the relevant include directive in your test.o: target; something like -Ipath/to/your/header.
Your compilation doesn't give the compiler the include path to find the header.
Instead, specify a base location and add the path to the compile. Otherwise if you can change the naza interface library, its install target should install the headers to a system (or $PREFIX/include) location.
test.o:
g++ -I$(NAZA_INTERFACE_LIB)/src/ -c test.cpp

Linking Intel MKL with Armadillo C++ Matrix Library

I have been having a number of issues with linking Intel MKL with Armadillo C++.
Im trying to do this on OSX.
I have installed Intel parallel_studio_xe_2016.3.068 as root so that its available across the whole system.
Here is my example code that I'm trying to run:
example.cpp
#include <iostream>
#include <armadillo>
using namespace std;
using namespace arma;
int main(int argc, const char * argv[]) {
// mkl_set_num_threads(4);
mat A = randu<mat>(1,2);
mat B = randu<mat>(2,1);
mat D;
double C = 0;
while (C == 0){
cout << A*B;
}
return 0;
}
I downloaded the armadillo 7.300.1 tar from sourceforge, unpacked it ran the following commands in terminal:
cd armadillo-7.300.1
cmake .
make
And then to compile my cpp file I used the link line advisor on intel site to get all the details I needed.
icpc -DMKL_ILP64 -qopenmp -I/opt/intel/mkl/include -I~/GithubRepos/PMIWork/armadillo-7.300.1/include -DARMA_DONT_USE_WRAPPER -L/opt/intel/mkl/lib -Wl,-rpath,/opt/intel/mkl/lib -lmkl_intel_ilp64 -lmkl_core -lmkl_intel_thread -lpthread -lm -ldl example.cpp -o example
However when I run the resulting executable I get a segmentation fault. If I remove the cout << then the code complies, runs but it only uses 1 single core. I thought that MKL is suppose to automatically scale to the whole CPU.
Would really appreciate any help with this.

How to compile a cpp and then link it to a shared library

I want to have the functions which are defined in another .cpp file become available in another simulation tool.
I found the following code in this question: -finstrument-functions doesn't work with dynamically loaded g++ shared objects (.so)
Trace.cpp
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
void __cyg_profile_func_enter(void *this_fn, void *call_site)
__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)
__attribute__((no_instrument_function));
}
#endif
void __cyg_profile_func_enter(void* this_fn, void* call_site)
{
printf("entering %p\n", (int*)this_fn);
}
void __cyg_profile_func_exit(void* this_fn, void* call_site)
{
printf("exiting %p\n", (int*)this_fn);
}
Trace.cpp is compiled by doing:
g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic MyLib.cpp MyLibStub.cpp Trace.cpp -o libMyLib.so.0.0
ln -s libMyLib.so.0.0 libMyLib.so.0
ln -s libMyLib.so.0.0 libMyLib.so
g++ MainStatic.cpp -g -Wall -lMyLib -L./ -o MainStatic
g++ MainDynamic.cpp -g -Wall -ldl -o MainDynamic
Note that I don't need: MyLib.cpp and MyLibStub.cpp.
Instead compiled Trace.cpp doing:
g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic Trace.cpp -o libMyLib.so.0.0
What I've tried:
The shared object where I want to have Trace.cpp is obtained by:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
I added -L and -l:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -L /home/user/Desktop/test/ -lMyLib -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
and got:
/usr/bin/ld: cannot find -lMyLib
I also tried:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins /home/user/Desktop/test/libMyLib.so.0.0 -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
which compiled successfully but the application crashed:
Error during startup: Cannot load library
'../../src//libveins.so': libMyLib.so.0: cannot open shared object
file: No such file or directory.
Question:
How to compile Trace.cpp correctly?
How to link it with the rest of the shared library?
As you might notice I am not very experienced with compiling, linking and similar. So, any extra explanation is very welcome!
As #Flexo restates what #EmployedRussian said in the linked question, the main point is to get your implementation of __cyg_profile_func_*** before the one provided by libc.so.6.
One method to do this, is to use the LD_PRELOAD environment variable. Here you can read what LD_PRELOAD does and how it works.
To use the LD_PRELOAD trick you will need to compile your implementation of the above-mentioned functions as a shared library.
You can do this by doing:
g++ -shared -fPIC myImp.cc -o myImp.so -ldl
Once you get the .so file, navigate to the directory where your executable is located and do:
LD_PRELOAD=<path/to/myImp.so>- ./<myExecutable>
For shared libraries, dynamic linking is used. Meaning:
resolving of some undefined symbols (is postponed) until a program is run.
By using LD_PRELOAD you resolve the symbols of your interest before letting the linked do that.
Here you have an implementation of myImp.cc, which I took from: https://groups.google.com/forum/#!topic/gnu.gcc.help/a-hvguqe10I
The current version lacks proper implementation for __cyg_profile_func_exit, and I have not been able to demangle the function names.
#ifdef __cplusplus
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
void __cyg_profile_func_enter(void *this_fn, void *call_site)__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)__attribute__((no_instrument_function));
}
#endif
static FILE *fp;
int call_level=0;
void * last_fn;
void __cyg_profile_func_enter(void *this_fn, void *call_site)
{
Dl_info di;
if (fp == NULL) fp = fopen( "trace.txt", "w" );
if (fp == NULL) exit(-1);
if ( this_fn!=last_fn) ++call_level;
for (int i=0;i<=call_level;i++)
{
fprintf(fp,"\t");
}
//fprintf(fp, "entering %p\n", (int *)this_fn);
fprintf(fp, "entering %p", (int *)this_fn);
if (dladdr(this_fn, &di)) {
fprintf(fp, " %s (%s)", di.dli_sname ? di.dli_sname : "<unknown>", di.dli_fname);
}
fputs("\n", fp);
(void)call_site;
last_fn = this_fn;
}
void __cyg_profile_func_exit(void *this_fn, void *call_site)
{
--call_level;
for (int i=0;i<=call_level;i++) fprintf(fp,"\t");
fprintf(fp, "exiting %p\n", (int *)this_fn);
(void)call_site;
}
Another option for function tracing which uses LD_PRELOAD is used by LTTng, in the section Function Tracing, but I have never used it...

undefined reference to symbol '_ZNSt8ios_base4InitD1Ev##GLIBCXX_3.4' building OpenCV on Ubuntu

I'm on Ubuntu Trusty and I'm building the following code with this command. I'm new to clang and I could use help debugging these errors. The cpp and hpp files these C bindings are from compile fine. I copied the headers from those files into the below file I have listed here, w.cpp
clang -std=c++11 w.cpp -o w `pkg-config --cflags --libs opencv`
Here are the errors:
/usr/bin/ld: /tmp/w-2a90f4.o: undefined reference to
symbol '_ZNSt8ios_base4InitD1Ev##GLIBCXX_3.4'
//usr/lib/x86_64-linux-gnu/libstdc++.so.6: error adding
symbols: DSO missing from command line
clang: error: linker command failed with exit code 1
(use -v to see invocation)
Here is the contents of w.cpp. I'm trying to benchmark code using
clang.
#include <opencv2/c/mat.hpp>
#include <opencv2/c/opencv_generated.hpp>
using namespace cv;
using namespace std;
using namespace flann;
using namespace cvflann;
void cv_delete(char* self) {
delete self;
}
Mat* cv_create_Mat() {
return new Mat();
}
BFMatcher* cv_create_BFMatcher(int normType, bool crossCheck) {
return new BFMatcher(normType, crossCheck);
}
int main () {
for( int a = 1; a < 20; a++)
{
Mat a = &cv_create_Mat();
cv_delete(a);
}
}
I had the same error using gcc instead of g++, I believe you must use clang++
clang++ -std=c++11 w.cpp -o w `pkg-config --cflags --libs opencv`
While compiling C++ files, its better to use
g++ client.cpp -Wall -lstdc++ -o client