Make file Linking issue Undefined symbols for architecture x86_64 - c++

I am working on getting a few files to link together using my make file and c++ and am getting the following error when running make.
g++ -bind_at_load `pkg-config --cflags opencv` -c -o compute_gist.o compute_gist.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o gist.o gist.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o standalone_image.o standalone_image.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o IplImageConverter.o IplImageConverter.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o GistCalculator.o GistCalculator.cpp
g++ -bind_at_load `pkg-config --cflags opencv` `pkg-config --libs opencv` compute_gist.o gist.o standalone_image.o IplImageConverter.o GistCalculator.o -o rungist
Undefined symbols for architecture x86_64:
"color_gist_scaletab(color_image_t*, int, int, int const*)", referenced from:
_main in compute_gist.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [rungist] Error 1
My makefile is as follows (Note, I don't need opencv bindings yet, but will be coding in opencv later.
CXX = g++
CXXFLAGS = -bind_at_load `pkg-config --cflags opencv`
LFLAGS = `pkg-config --libs opencv`
SRC = \
compute_gist.cpp \
gist.cpp \
standalone_image.cpp \
IplImageConverter.cpp \
GistCalculator.cpp
OBJS = $(SRC:.cpp=.o)
rungist: $(OBJS)
$(CXX) $(CXXFLAGS) $(LFLAGS) $(OBJS) -o $#
all: rungist
clean:
rm -rf $(OBJS) rungist
The method header is located in gist.h
float *color_gist_scaletab(color_image_t *src, int nblocks, int n_scale, const int *n_orientations);
And the method is defined in gist.cpp
float *color_gist_scaletab(color_image_t *src, int w, int n_scale, const int *n_orientation) {
And finally the compute_gist.cpp (main file)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gist.h"
static color_image_t *load_ppm(const char *fname) {
FILE *f=fopen(fname,"r");
if(!f) {
perror("could not open infile");
exit(1);
}
int width,height,maxval;
if(fscanf(f,"P6 %d %d %d",&width,&height,&maxval)!=3 || maxval!=255) {
fprintf(stderr,"Error: input not a raw PPM with maxval 255\n");
exit(1);
}
fgetc(f); /* eat the newline */
color_image_t *im=color_image_new(width,height);
int i;
for(i=0;i<width*height;i++) {
im->c1[i]=fgetc(f);
im->c2[i]=fgetc(f);
im->c3[i]=fgetc(f);
}
fclose(f);
return im;
}
static void usage(void) {
fprintf(stderr,"compute_gist options... [infilename]\n"
"infile is a PPM raw file\n"
"options:\n"
"[-nblocks nb] use a grid of nb*nb cells (default 4)\n"
"[-orientationsPerScale o_1,..,o_n] use n scales and compute o_i orientations for scale i\n"
);
exit(1);
}
int main(int argc,char **args) {
const char *infilename="/dev/stdin";
int nblocks=4;
int n_scale=3;
int orientations_per_scale[50]={8,8,4};
while(*++args) {
const char *a=*args;
if(!strcmp(a,"-h")) usage();
else if(!strcmp(a,"-nblocks")) {
if(!sscanf(*++args,"%d",&nblocks)) {
fprintf(stderr,"could not parse %s argument",a);
usage();
}
} else if(!strcmp(a,"-orientationsPerScale")) {
char *c;
n_scale=0;
for(c=strtok(*++args,",");c;c=strtok(NULL,",")) {
if(!sscanf(c,"%d",&orientations_per_scale[n_scale++])) {
fprintf(stderr,"could not parse %s argument",a);
usage();
}
}
} else {
infilename=a;
}
}
color_image_t *im=load_ppm(infilename);
//Here's the method call -> :(
float *desc=color_gist_scaletab(im,nblocks,n_scale,orientations_per_scale);
int i;
int descsize=0;
//compute descriptor size
for(i=0;i<n_scale;i++)
descsize+=nblocks*nblocks*orientations_per_scale[i];
descsize*=3; // color
//print descriptor
for(i=0;i<descsize;i++)
printf("%.4f ",desc[i]);
printf("\n");
free(desc);
color_image_delete(im);
return 0;
}
Any help would be greatly appreciated. I hope this is enough info. Let me know if I need to add more.

I suspect that color_gist_scaletab should be declared as extern "C" in your header file:
extern "C" {
float *color_gist_scaletab(color_image_t *src, int nblocks, int n_scale, const int *n_orientations);
}

Your link command line is incorrect. See this answer.
However, that is likely not the problem you are seeing here.
What do the following commands print?
file gist.o
nm gist.o | grep color_gist_scaletab
I also see this very similar question. But there, color_gist_scaletab comes from gist.c, not gist.cpp. You didn't just rename gist.c to gist.cpp, did you? Don't do that.

Related

gstreamer exception in gst_element_get_state runnig opencv program

I am running an OpenCV application that uses also other external libraries such as Poco libraries, jsoncpp, and SDL.
All the libraries have been compiled locally and I am linking them through a Makefile.
The program streams the video from a webcam and should catch the input from the keyboard (a character for example) to do something.
All it is under Ubuntu 18.04; the C++ source code is correct because under OSX it runs without problems and it is doing what being expected (If needed I will append an example of the source code).
The program runs and does not stop but it does not catch the keyboard input and as soon as it starts I get the error
(process:11477): GStreamer-CRITICAL **: 18:44:25.567: gst_element_get_state: assertion 'GST_IS_ELEMENT (element)' failed
OpenCV | GStreamer warning: GStreamer: unable to query pipeline state (/home/fra/Documents/openCV/openCV/modules/videoio/src/cap_gstreamer.cpp:420)
I have installed the gstreamer libraries because they were required by opencv and I am including and linking them in the Makefile like this (see the complete Makefile later):
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-1.0.pc`\
...
and
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-1.0.pc`\
....
Have anyone had the same problem? What is generating the exception?
I am thinking the error is related to Opencv deendencies but I am not sure is not a problem related to SDL2.0.
SOURCE CODE OF THE C++ PROGRAM
Here is a minimal working example: clicking the left and right buttons of the mouse works (catched directly with Opencv callbacks) while pressing and releasing the keyboard buttons does not call the proper SDL callback.
The script can be launched with ./executable camID anyNameYouWant where camID is an integer (typically 0 or 1) that identifies the cam you want to use.
#ifndef __OPENCV__
#define __OPENCV__
#include "opencv2/opencv.hpp"
#endif
#include<iostream>
//#include "utils.hpp"
//#include "constants.hpp"
#include<unistd.h>
#include <vector>
#include<SDL.h>
#include <SDL_events.h>
using namespace cv;
using namespace std;
static const int delay = 2;
#define WINDOW_SCALE 1.7
//const int SCREEN_WIDTH = 640;
//const int SCREEN_HEIGHT = 480;
void onTrackbar_changed(int, void* data);
//void onThreshold_changed(int, void* data);
void onMouse(int evt, int x, int y, int flags, void* param);
void PrintKeyInfo( SDL_KeyboardEvent *key );
int keyboardCallback(SDL_KeyboardEvent ev);
//InputStateContext context;
int main(int argc, char* argv[])
{
/* Initialise SDL */
if( SDL_Init( SDL_INIT_VIDEO ) < 0)
{
fprintf( stderr, "Could not initialise SDL: %s\n", SDL_GetError() );
exit( -1 );
}
string host;
unsigned int port;
const String sourceReference = argv[1];
int camNum;
string sensorName;
try
{
camNum = stoi(sourceReference); // throws std::length_error
}
catch (const std::exception& e)// reference to the base of a polymorphic object
{
std::cout<<"Exception: " << e.what()<<endl; // information from length_error printed
return -1;
}
if (argc>4)
{
try
{
host = argv[2];
port = atoi(argv[3]);
sensorName = argv[4];
}
catch (const std::exception& e)
{
cout<<"impossible to convert host or port"<<endl;
return -1;
}
}
else if(argc>2)
{
cout<<"argumetns less than 4"<<endl;
host = "http://localhost";
port = 3456;
sensorName = argv[2];
cout<<argc<<endl;
cout<<"sensor name set from arguments: "<< sensorName<<endl;
}
else
{
cout<<"stopping execution: too few arguments."<<endl;
return -1;
}
VideoCapture cam(camNum);
/* or
VideoCapture captUndTst;
captUndTst.open(sourceCompareWith);*/
if ( !cam.isOpened())
{
cout << "Could not open reference " << sourceReference << endl;
return -1;
}
namedWindow("Camera", WINDOW_NORMAL);
Mat frame;
SDL_Event keyboardEvent;
cam>>frame;
resize(frame, frame, cv::Size(frame.cols/WINDOW_SCALE, frame.rows/WINDOW_SCALE));
resizeWindow("Camera", cv::Size(frame.cols/WINDOW_SCALE, frame.rows/WINDOW_SCALE));
setMouseCallback("Camera", onMouse, &frame);
while(1)
{
while( SDL_PollEvent( &keyboardEvent) )
{
switch( keyboardEvent.type )
{
/* Keyboard event */
/* Pass the event data onto PrintKeyInfo() */
case SDL_KEYDOWN:
break;
case SDL_KEYUP:
keyboardCallback(keyboardEvent.key);
break;
/* SDL_QUIT event (window close) */
case SDL_QUIT:
return 0;
break;
default:
break;
}
}
Mat frame_out;
frame_out = frame.clone();
cam>>frame;
resize(frame_out, frame_out, cv::Size(frame.cols/WINDOW_SCALE, frame.rows/WINDOW_SCALE));
imshow("Camera", frame_out);
/* A delay is needed to show (it actually wait for an input)*/
if(waitKey(delay)>delay){;}
}
return 0;
}
void onMouse(int evt, int x, int y, int flags, void* param)
{
if(evt == EVENT_LBUTTONDOWN)
{
cout<<"Left button pressed"<<endl;
}
else if(evt == EVENT_RBUTTONDOWN)
{
cout<<"Right button pressed"<<endl;
}
}
int keyboardCallback(SDL_KeyboardEvent ev)
{
switch(ev.keysym.sym)
{
case(SDLK_a):
cout<<"calling context keyboardA"<<endl;
break;
case(SDLK_e):
cout<<"calling context keyboardE"<<endl;
break;
case(SDLK_m):
cout<<"calling context keyboardM"<<endl;
break;
case SDLK_UP:
case SDLK_RIGHT:
cout<<"calling context RIGHT ARROW"<<endl;
break;
case SDLK_DOWN:
case SDLK_LEFT:
cout<<"calling context RIGHT ARROW"<<endl;
break;
case (SDLK_RETURN):
cout<<"calling context RIGHT ARROW"<<endl;
break;
default:
break;
}
return 0;
}
**COMPILATION **
To compile the script I use the following Makefile. The paths of the libraries are relatives (except the gstreamer libraries) since I built them in a local folder.
CXX = g++
CXXFLAGS = -std=c++11
INC_PATH = `pkg-config --cflags ../openCV/build/lib/pkgconfig/opencv.pc` \
`pkg-config --cflags ../SDL2-2.0.8/instDir/lib/pkgconfig/sdl2.pc` \
`pkg-config --cflags ../jsoncpp/build/pkg-config/jsoncpp.pc` \
-I ../poco/instDir/include/ \
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-1.0.pc`\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-allocators-1.0.pc`\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-app-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-audio-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-bad-audio-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-bad-video-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-base-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-check-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-codecparsers-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-controller-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-fft-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-gl-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-insertbin-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-mpegts-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-net-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-pbutils-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-player-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-plugins-bad-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-plugins-base-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-plugins-good-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-riff-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-rtp-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-rtsp-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-sdp-1.0.pc`\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-tag-1.0.pc`\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-video-1.0.pc `\
`pkg-config --cflags /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-webrtc-1.0.pc`
#LIB_PATH = -L../cmake_bin_dir/lib/ ./gainput/build/lib -L../SDL2-2.0.8/build/ -L../SDL2-2.0.8/build/lib
LIBS = `pkg-config --libs ../openCV/build//lib/pkgconfig/opencv.pc` \
`pkg-config --libs ../SDL2-2.0.8/instDir/lib/pkgconfig/sdl2.pc` \
`pkg-config --libs ../jsoncpp/build/pkg-config/jsoncpp.pc` \
-L../poco/instDir/lib/ -lPocoNetd -lPocoUtild -lPocoFoundationd \
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-1.0.pc`\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-allocators-1.0.pc`\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-app-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-audio-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-bad-audio-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-bad-video-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-base-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-check-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-codecparsers-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-controller-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-fft-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-gl-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-insertbin-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-mpegts-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-net-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-pbutils-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-player-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-plugins-bad-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-plugins-base-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-plugins-good-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-riff-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-rtp-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-rtsp-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-sdp-1.0.pc`\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-tag-1.0.pc`\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-video-1.0.pc `\
`pkg-config --libs /usr/lib/x86_64-linux-gnu/pkgconfig/gstreamer-webrtc-1.0.pc`
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR=$(SOURCEDIR)/obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: parking
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
parking: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) $^ -o $# $(LIBS)
-include $(DEPENDS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) -MMD -MP -c $< -o $#

How to compile OpenCV with Boost::Python?

I'm trying to compile OpenCV in C++ with boost::python but I keep getting a linker error that I can't quite resolve.
Here is the code below.
cascade_handler.cpp
#include <iostream>
#include <boost/python.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ocl/ocl.hpp>
#include "cascade_handler.h"
using namespace std;
using namespace boost::python;
void CascadeHandler::cascade_classifier_cpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors){
/*cv::Mat image;
cv::CascadeClassifier cascade_classifier;
cascade_classifier.load(*cascade_file);
cascade_classifier.detectMultiScale(image, objects, scale_factor, min_neighbors, 0 | CASCADE_SCALE_IMAGE, Size(20, 20));
*/
}
void CascadeHandler::cascade_classifier_gpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors){
/*Mat image;
cv::CascadeClassifier cascade_classifier;
*/
}
void CascadeHandler::handle(const string cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors)
{
CascadeHandler cascade_handler;
cv::CascadeClassifier cascade_classifier;
//ocl::Context context;
/*
if (!cascade_classifier.load(cascade_file)){
cout << "[!] Error: You must load a Cascade file\n";
}
if (objects.empty()){
}
if (scale_factor == 0){
cout << "[!] Error: Unacceptable Scale Factor\n";
}
if (min_neighbors == 0){
cout << "[!] Error: Unacceptable Minimum Neighbors\n";
}
if (context.ndevices()){
cascade_handler.cascade_classifier_gpu(&cascade_file, objects, scale_factor, min_neighbors);
}
else if (!context.ndevices()){
cascade_handler.cascade_classifier_cpu(&cascade_file, objects, scale_factor, min_neighbors);
}
*/
}
void cascade_handler_wrapper(const string cascade_file, std::vector<cv::Rect>& objects,
double scale_factor, int min_neighbors){
CascadeHandler cascade_handler;
cascade_handler.handle(cascade_file, objects, scale_factor, min_neighbors);
}
BOOST_PYTHON_MODULE(cascade_handler){
def("handle", cascade_handler_wrapper);
}
The Header file
#ifndef _CASCADE_HANDLER
#define _CASCADE_HANDLER
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ocl/ocl.hpp>
using namespace std;
class CascadeHandler
{
public:
void cascade_classifier_cpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors);
void cascade_classifier_gpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors);
void handle(const string cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors);
};
#endif
The Makefile
CPP = g++
CPPFLAGS = -g -Wall -std=c++11
INCLUDES = -I /usr/local/include
LDFLAGS = -L /usr/local/lib
ARCH := $$(getconf LONG_BIT)
CUDA_PATH = /opt/cuda
CUDA_LDFLAGS = -L$(CUDA_PATH)/lib$(ARCH)
CUDA_INCLUDES = -I$(CUDA_PATH)/include
OPENCV_LDFLAGS = $(CUDA_LDFLAGS)
OPENCV_LIBS = $$(pkg-config --libs opencv)
OPENCV_INCLUDES = $$(pkg-config --cflags opencv) $(CUDA_INCLUDES)
PYTHON_VER = 2
ifeq ($(PYTHON_VER), 2)
BOOST_LIBS = -lboost_python
else
BOOST_LIBS = -lboost_python$(PYTHON_VER)
endif
PYTHON_LIBS = $$(pkg-config --libs python$(PYTHON_VER))
PYTHON_INCLUDES = $$(pkg-config --cflags python$(PYTHON_VER))
TARGET = cascade_handler
all: $(TARGET).so
$(TARGET).so: $(TARGET).o
$(CPP) -shared -Wl,--export-dynamic $(LDFLAGS) \
$(OPENCV_LIBS) $(BOOST_LIBS) $(PYTHON_LIBS) \
$(TARGET).o -o $(TARGET).so
$(TARGET).o: $(TARGET).cpp
$(CPP) $(CPPFLAGS) $(INCLUDES) $(OPENCV_INCLUDES) $(PYTHON_INCLUDES) \
-fPIC -c $(TARGET).cpp
clean:
rm -f *.o *.so
And the Output
g++ -shared -Wl,--export-dynamic -L /usr/local/lib \
$(pkg-config --libs opencv) -lboost_python $(pkg-config --libs python2) \
cascade_handler.o -o cascade_handler.so
ld: unknown option: --export-dynamic
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [cascade_handler.so] Error 1
The linker error is the thing I can't quite fix. I wanted to have everything compile on a Makefile because I couldn't find a way to compile OpenCV with the setup.py you normally use when using boost::python. I've also read that some people have been using numpy to wrap their code in and then compile that way, but I was wondering if this method may also work? I also have most of the code commented out because I just wanted to test if it would compile by just have the class cv::CascadeClassifier cascade_classifier;

Writing makefile to compile several binaries

I am trying to write a Makefile to compile 87 files with the following names:
file1.c, file2.c file3.c .... file87.c
I am trying to compile them into separate binaries with names:
file1, file2, file3 .... file87
In the Makefile I need to define following variables for each and every one of them. This is what I had originally.
FILE1 = file1
$(FILE1)_SRC := \
mydir/file1.c \
mydir/another.c
$(FILE1)_CFLAGS := `pkg-config --cflags glib-2.0`
$(FILE1)_LDFLAGS := -L. `pkg-config --libs glib-2.0`
FILE2 = file2
$(FILE2)_SRC := \
mydir/file2.c \
mydir/another.c
$(FILE2)_CFLAGS := `pkg-config --cflags glib-2.0`
$(FILE2)_LDFLAGS := -L. `pkg-config --libs glib-2.0`
Also at the end of the Makefile I need to store the names of the binaries
binaries = $(FILE1) $(FILE2) ...... $(FILE87)
I explored loops and define directive in make but I cannot understand how can I do this neatly in a non-cumbersome manner. Please note the CFLAGS and LDFLAGS are same for all of them.
Any inputs or alternative approaches to writing the Makefile are very welcome.
I wrote this based on seldon's answer below, but this gives an error:
SRCS = $(wildcard mydir/*.c)
TGTS = $(SRCS:%.c=%)
CFLAGS = $$(pkg-config --cflags glib-2.0)
LDFLAGS = -L.
LDLIBS = $$(pkg-config --libs glib-2.0)
all: $(TGTS)
#echo $(SRCS)
#echo $(TGTS)
$(TGTS) : % : %.o another.o
#clean:
# rm -f $(TGTS) *.o
#.PHONY: all clean
$ make
cc $(pkg-config --cflags glib-2.0) -c -o mydir/another.o mydir/another.c
make: *** No rule to make target `another.o', needed by `mydir/another'. Stop.
Source:
another.c
# include <stdio.h>
# include <stdlib.h>
void print_string(const char * file_name, int lineno, const char * func_name) {
printf("%s %d %s\n", file_name, lineno, func_name);
}
file01.c
int main() {
print_string(__FILE__, __LINE__, __func__);
}
Any help appreciated.
If the variables are the same for all programs, you could use a static pattern rule like this:
SRCS = $(wildcard file*.c)
TGTS = $(SRCS:%.c=%)
CFLAGS = $$(pkg-config --cflags glib-2.0)
LDFLAGS = -L.
LDLIBS = $$(pkg-config --libs glib-2.0)
all: $(TGTS)
$(TGTS) : % : %.o another.o
clean:
rm -f $(TGTS) *.o
.PHONY: all clean

C++ code compiles fine with normal V8 engine, fails to build with V8 provided by Node

Makefile:
CC:=g++
OUTFILE?=addon
SOURCE?=src
CFLAGS+=-Iinclude -lv8 -m64
.PHONY: all clean
all:
$(CC) $(CFLAGS) -o $(OUTFILE) `ls $(SOURCE)/*.cc`
clean:
rm -f $(OUTFILE)
addon.h:
#ifndef __addon_h
#define __addon_h
#define BUILDING_NODE_EXTENSION
#define ADDON_VERSION "0.0.1"
#ifdef BUILDING_NODE_EXTENSION
#include <node/node.h>
#include <node/v8.h>
#else
#include <v8.h>
#endif
using namespace v8;
void init(Handle<Object> exports);
Handle<Object> setupExports(Handle<Object> exports);
#endif
addon.cc:
#include <cstdlib>
#include <cstdio>
#include <addon.h>
using namespace v8;
#ifndef BUILDING_NODE_EXTENSION
int main(int argc, char **argv) {
Isolate *isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
Handle<Context> context = Context::New(isolate);
Context::Scope context_scope(context);
Handle<Object> exports = Object::New();
init(exports);
printf("Version: %s\n", *String::Utf8Value(exports->Get(String::New("version"))));
return 0;
}
#else
int main() {
printf("This is a module compiled for Node.\nPlease use require in Node to use this file.\n");
return 0;
}
#endif
void init(Handle<Object> exports) {
setupExports(exports);
}
Handle<Object> setupExports(Handle<Object> exports) {
// Set version number.
exports->Set(String::New("version"), String::New(ADDON_VERSION));
return exports;
}
#ifdef BUILDING_NODE_EXTENSION
NODE_MODULE(addon, init)
#endif
When compiling the above code with the normal V8 engine without BUILDING_NODE_EXTENSION defined, the output is what we expect:
❱ make && ./addon
g++ -Iinclude -lv8 -m64 -o addon `ls src/*.cc`
Version: 0.0.1
When compiling with BUILDING_NODE_EXTENSION defined, using Node's <node/node.h> and <node/v8.h> for includes instead of the normal <v8.h>, I get this:
❱ make && ./addon
g++ -Iinclude -lv8 -m64 -o addon `ls src/*.cc`
Undefined symbols for architecture x86_64:
"v8::String::New(char const*, int)", referenced from:
setupExports(v8::Handle<v8::Object>) in ccRntYkS.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [all] Error 1
Anyone have any idea what is going wrong here?
Building with node-gyp solved the problem.
Face. Palm.
Makefile change:
CC:=g++
OUTFILE?=addon
SOURCE?=src
CFLAGS+=-Iinclude -lv8 -m64
.PHONY: all clean
all:
if [ -d build ]; then \
node-gyp build; \
else \
$(CC) $(CFLAGS) -o $(OUTFILE) `ls $(SOURCE)/*.cc`; \
fi;
clean:
rm -f $(OUTFILE)

cuda shared library linking: undefined reference to cudaRegisterLinkedBinary

Goal:
create a shared library containing my CUDA kernels that has a CUDA-free wrapper/header.
create a test executable for the shared library.
Problem
shared library MYLIB.so seems to compile fine. (no problem).
Error in linking:
./libMYLIB.so: undefined reference to __cudaRegisterLinkedBinary_39_tmpxft_000018cf_00000000_6_MYLIB_cpp1_ii_74c599a1
simplified makefile:
libMYlib.so : MYLIB.o
g++ -shared -Wl,-soname,libMYLIB.so -o libMYLIB.so MYLIB.o -L/the/cuda/lib/dir -lcudart
MYLIB.o : MYLIB.cu MYLIB.h
nvcc -m64 -arch=sm_20 -dc -Xcompiler '-fPIC' MYLIB.cu -o MYLIB.o -L/the/cuda/lib/dir -lcudart
test : test.cpp libMYlib.so
g++ test.cpp -o test -L. -ldl -Wl,-rpath,. -lMYLIB -L/the/cuda/lib/dir -lcudart
indeed
nm libMYLIB.so shows that all CUDA api functions are "undefined symbols":
U __cudaRegisterFunction
U __cudaRegisterLinkedBinary_39_tmpxft_0000598c_00000000_6_CUPA_cpp1_ii_74c599a1
U cudaEventRecord
U cudaFree
U cudaGetDevice
U cudaGetDeviceProperties
U cudaGetErrorString
U cudaLaunch
U cudaMalloc
U cudaMemcpy
So CUDA somehow did not get linked to the shared library MYLIB.so
What am I missing?
CUDA did not even get linked to the object file somehow:
nm MYLIB.o
U __cudaRegisterFunction
U __cudaRegisterLinkedBinary_39_tmpxft_0000598c_00000000_6_CUPA_cpp1_ii_74c599a1
U cudaEventRecord
U cudaFree
U cudaGetDevice
U cudaGetDeviceProperties
U cudaGetErrorString
U cudaLaunch
U cudaMalloc
U cudaMemcpy
(same as above)
Here's an example linux shared object creation along the lines you indicated:
create a shared library containing my CUDA kernels that has a
CUDA-free wrapper/header.
create a test executable for the shared library.
First the shared library. The build commands for this are as follows:
nvcc -arch=sm_20 -Xcompiler '-fPIC' -dc test1.cu test2.cu
nvcc -arch=sm_20 -Xcompiler '-fPIC' -dlink test1.o test2.o -o link.o
g++ -shared -o test.so test1.o test2.o link.o -L/usr/local/cuda/lib64 -lcudart
It seems you may be missing the second step above in your makefile, but I haven't analyzed if there are any other issues with your makefile.
Now, for the test executable, the build commands are as follows:
g++ -c main.cpp
g++ -o testmain main.o test.so
To run it, simply execute the testmain executable, but be sure the test.so library is on your LD_LIBRARY_PATH.
These are the files I used for test purposes:
test1.h:
int my_test_func1();
test1.cu:
#include <stdio.h>
#include "test1.h"
#define DSIZE 1024
#define DVAL 10
#define nTPB 256
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
__global__ void my_kernel1(int *data){
int idx = threadIdx.x + (blockDim.x *blockIdx.x);
if (idx < DSIZE) data[idx] =+ DVAL;
}
int my_test_func1(){
int *d_data, *h_data;
h_data = (int *) malloc(DSIZE * sizeof(int));
if (h_data == 0) {printf("malloc fail\n"); exit(1);}
cudaMalloc((void **)&d_data, DSIZE * sizeof(int));
cudaCheckErrors("cudaMalloc fail");
for (int i = 0; i < DSIZE; i++) h_data[i] = 0;
cudaMemcpy(d_data, h_data, DSIZE * sizeof(int), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy fail");
my_kernel1<<<((DSIZE+nTPB-1)/nTPB), nTPB>>>(d_data);
cudaDeviceSynchronize();
cudaCheckErrors("kernel");
cudaMemcpy(h_data, d_data, DSIZE * sizeof(int), cudaMemcpyDeviceToHost);
cudaCheckErrors("cudaMemcpy 2");
for (int i = 0; i < DSIZE; i++)
if (h_data[i] != DVAL) {printf("Results check failed at offset %d, data was: %d, should be %d\n", i, h_data[i], DVAL); exit(1);}
printf("Results check 1 passed!\n");
return 0;
}
test2.h:
int my_test_func2();
test2.cu:
#include <stdio.h>
#include "test2.h"
#define DSIZE 1024
#define DVAL 20
#define nTPB 256
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
__global__ void my_kernel2(int *data){
int idx = threadIdx.x + (blockDim.x *blockIdx.x);
if (idx < DSIZE) data[idx] =+ DVAL;
}
int my_test_func2(){
int *d_data, *h_data;
h_data = (int *) malloc(DSIZE * sizeof(int));
if (h_data == 0) {printf("malloc fail\n"); exit(1);}
cudaMalloc((void **)&d_data, DSIZE * sizeof(int));
cudaCheckErrors("cudaMalloc fail");
for (int i = 0; i < DSIZE; i++) h_data[i] = 0;
cudaMemcpy(d_data, h_data, DSIZE * sizeof(int), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy fail");
my_kernel2<<<((DSIZE+nTPB-1)/nTPB), nTPB>>>(d_data);
cudaDeviceSynchronize();
cudaCheckErrors("kernel");
cudaMemcpy(h_data, d_data, DSIZE * sizeof(int), cudaMemcpyDeviceToHost);
cudaCheckErrors("cudaMemcpy 2");
for (int i = 0; i < DSIZE; i++)
if (h_data[i] != DVAL) {printf("Results check failed at offset %d, data was: %d, should be %d\n", i, h_data[i], DVAL); exit(1);}
printf("Results check 2 passed!\n");
return 0;
}
main.cpp:
#include <stdio.h>
#include "test1.h"
#include "test2.h"
int main(){
my_test_func1();
my_test_func2();
return 0;
}
When I compile according to the commands given, and run ./testmain I get:
$ ./testmain
Results check 1 passed!
Results check 2 passed!
Note that if you prefer, you may generate a libtest.so instead of test.so, and then you may use a modified build sequence for the test executable:
g++ -c main.cpp
g++ -o testmain main.o -L. -ltest
I don't believe it makes any difference, but it may be more familiar syntax.
I'm sure there is more than one way to accomplish this. This is just an example.
You may wish to also review the relevant section of the nvcc manual and also review the examples.
EDIT: I tested this under cuda 5.5 RC, and the final application link step complained about not finding the cudart lib (warning: libcudart.so.5.5., needed by ./libtest.so, not found). However the following relatively simple modification (example Makefile) should work under either cuda 5.0 or cuda 5.5.
Makefile:
testmain : main.cpp libtest.so
g++ -c main.cpp
g++ -o testmain -L. -ldl -Wl,-rpath,. -ltest -L/usr/local/cuda/lib64 -lcudart main.o
libtest.so : link.o
g++ -shared -Wl,-soname,libtest.so -o libtest.so test1.o test2.o link.o -L/usr/local/cuda/lib64 -lcudart
link.o : test1.cu test2.cu test1.h test2.h
nvcc -m64 -arch=sm_20 -dc -Xcompiler '-fPIC' test1.cu test2.cu
nvcc -m64 -arch=sm_20 -Xcompiler '-fPIC' -dlink test1.o test2.o -o link.o
clean :
rm -f testmain test1.o test2.o link.o libtest.so main.o
The other answers did not work for me (maybe because I’m using cuda 10).
The solution that worked for me was compiling the cuda files as:
nvcc -dc -o cuda_file.o cuda_file.cu
Than compiling the c++ file as:
g++ -c -o cpp_file.o cpp_file.cpp
And finally linking all using nvcc:
nvcc -o my_prog cpp_file.o cuda_file.o -lcudart -lcuda -L<other stuff>
Don’t take this code literally. But the core of the solution to the error was using nvcc instead of g++ in the final linking step.