2015-10-26 4 views
0

Я хочу написать программу на C++, которая использует две либрары libgphoto2 и opencv3.0. Поэтому я хочу включить собственный файл заголовка, который содержит некоторые функции, которые используют функции, определенные в библиотеке libgphoto2, в мой основной исходный код, в котором я импортирую opencv. Второй файл заголовка определяет только некоторые константы и не использует внешнюю библиотеку.Как связать две библиотеки с моей программой с помощью cmake?

Обе библиотеки установлены функционально на моем macbook. Я могу написать и скомпилировать рабочие программы, которые используют любой из них, используя cmake, но я действительно не знаю синтаксиса cmake, чтобы решить проблему выше ... btw: find_package работает для обеих библиотек!

Структура папки выглядит следующим образом:

./camera_cv 
./camera_cv/CMakeLists.txt 
./camera_cv/src 
./camera_cv/src/takeShowAdjust.cpp 
./camera_cv/src/mh_camera_control.hpp 
./camera_cv/src/cv_supplement.hpp 

Мой CMakeLists.txt файл:

cmake_minimum_required(VERSION 2.8) 
project(opencvTutorial) 

SET(CMAKE_CXX_FLAGS_DEBUG "-g -ggdb") 
SET(CMAKE_CXX_FLAGS_RELEASE "-Ofast -DNDEBUG -march=native") 

SET(CMAKE_BUILD_TYPE DEBUG) 

find_package(Gphoto2 REQUIRED) 
find_package(OpenCV 3.0.0 REQUIRED) 

include_directories(${GPHOTO2_INCLUDE_DIR} ${OpenCV_INCLUDE_DIRS}) 
add_executable(TakeShowAdjust src/takeShowAdjust.cpp src/cv_supplement.hpp src/mh_camera_control.hpp) 
target_link_libraries(TakeShowAdjust ${LIBGPHOTO2_LIBRARIES} ${OpenCV_LIBS} -lm) 

# --- Install --- 

SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin") 
INSTALL(TARGETS 
    TakeShowAdjust 
    DESTINATION ${BINDIR}) 

Typing $ CMake. записывает файлы сборки без каких-либо ошибок. Но потом, если я типа $ сделать, то я получаю следующие ошибки:

$ make 
Scanning dependencies of target TakeShowAdjust 
[ 50%] Building CXX object CMakeFiles/TakeShowAdjust.dir/src/takeShowAdjust.cpp.o 
[100%] Linking CXX executable TakeShowAdjust 
Undefined symbols for architecture x86_64: 
    "_gp_camera_capture", referenced from: 
     capture(char const*) in takeShowAdjust.cpp.o 
    "_gp_camera_file_delete", referenced from: 
     capture(char const*) in takeShowAdjust.cpp.o 
    "_gp_camera_file_get", referenced from: 
     capture(char const*) in takeShowAdjust.cpp.o 
    "_gp_camera_free", referenced from: 
     initialize_camera() in takeShowAdjust.cpp.o 
    "_gp_camera_get_config", referenced from: 
     get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
     set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
    "_gp_camera_init", referenced from: 
     initialize_camera() in takeShowAdjust.cpp.o 
    "_gp_camera_new", referenced from: 
     initialize_camera() in takeShowAdjust.cpp.o 
    "_gp_camera_set_config", referenced from: 
     set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
    "_gp_camera_unref", referenced from: 
     close_camera() in takeShowAdjust.cpp.o 
     _main in takeShowAdjust.cpp.o 
    "_gp_camera_wait_for_event", referenced from: 
     capture(char const*) in takeShowAdjust.cpp.o 
    "_gp_context_new", referenced from: 
     initialize_camera() in takeShowAdjust.cpp.o 
    "_gp_context_set_error_func", referenced from: 
     initialize_camera() in takeShowAdjust.cpp.o 
    "_gp_context_set_message_func", referenced from: 
     initialize_camera() in takeShowAdjust.cpp.o 
    "_gp_context_unref", referenced from: 
     close_camera() in takeShowAdjust.cpp.o 
     _main in takeShowAdjust.cpp.o 
    "_gp_file_free", referenced from: 
     capture(char const*) in takeShowAdjust.cpp.o 
    "_gp_file_new_from_fd", referenced from: 
     capture(char const*) in takeShowAdjust.cpp.o 
    "_gp_widget_free", referenced from: 
     get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
     set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
    "_gp_widget_get_child_by_label", referenced from: 
     get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
     set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
    "_gp_widget_get_child_by_name", referenced from: 
     get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
     set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
    "_gp_widget_get_type", referenced from: 
     get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
     set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
    "_gp_widget_get_value", referenced from: 
     get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
    "_gp_widget_set_value", referenced from: 
     set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 
make[2]: *** [TakeShowAdjust] Error 1 
make[1]: *** [CMakeFiles/TakeShowAdjust.dir/all] Error 2 
make: *** [all] Error 2 

Исходные коды:

takeShowAdjust.cpp:

#include <vector> 
#include <iostream> 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <cstdarg> 
#include <fcntl.h> 
#include <opencv2/opencv.hpp> 

#include "../src/cv_supplement.hpp" 
#include "../src/mh_camera_control.hpp" 

#define killall_PTPCamera system("killall PTPCamera"); 

using namespace cv; 
using namespace std; 

int main(int argc, char *argv[]) { 
    // Load Camera 
    initialize_camera(); 
    // take picture 
    char filename[256]; 
    int i = 1; 
    snprintf(filename, 256, "shot-%04d.jpg", i++); 
    printf("Capturing to file %s\n", filename); 
    capture(filename); 


    // load image 
    Mat img = imread(filename, CV_LOAD_IMAGE_COLOR); 

    // show image 
    namedWindow("original", WINDOW_AUTOSIZE); 
    moveWindow("original", POS_00); 
    imshow("original", img); 
    waitKey(0); 

    close_camera(); 
    return 0; 
} 

mh_camera_control.hpp:

#ifndef MH_CAMERA_CONTROL 
#define MH_CAMERA_CONTROL 

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <cstdarg> 
#include <fcntl.h> 
#include <gphoto2/gphoto2.h> 

#define killall_PTPCamera system("killall PTPCamera"); 

Camera *camera; 
GPContext *context; 

int initialize_camera(void); 
void close_camera(void); 
int capture (const char *filename); 
static int _lookup_widget(CameraWidget*widget, const char *key, CameraWidget **child); 
int get_config_value_string (const char *key, char **str, GPContext *contxt = context, Camera *cam = camera); 
int set_config_value_string (const char *key, const char *val, GPContext *contxt = context, Camera *cam = camera); 
void error_func(GPContext *context, const char *format, va_list args, void *data); 
void message_func(GPContext *context, const char *format, va_list args, void *data); 


int initialize_camera(void){ 
    killall_PTPCamera; 
    gp_camera_new(&camera); 
    context = gp_context_new(); 

    gp_context_set_error_func(context, (GPContextErrorFunc)error_func, NULL); 
    gp_context_set_message_func(context, (GPContextStatusFunc)message_func, NULL); 

    int ret = gp_camera_init(camera, context); 
    if(ret < GP_OK){ 
     printf("No camera auto detected.\n"); 
     gp_camera_free(camera); 
     return 1; 
    } 
    return 0; 
} 

void close_camera(void){ 
    gp_camera_unref(camera); 
    gp_context_unref(context); 
} 

int capture (const char *filename){ 
    int fd, retval; 
    CameraFile *file; 
    CameraFilePath camera_file_path; 

    //take a shot 
    retval = gp_camera_capture(camera, GP_CAPTURE_IMAGE, &camera_file_path, context); 
    if (retval){ 
     // do some error handling (return from function??) 
    } 
    printf("Pathname on the camera: %s/%s\n", camera_file_path.folder, camera_file_path.name); 
    fd = open(filename, O_CREAT | O_WRONLY, 0644); 
    // create new CameraFile object from a file descriptor 
    retval = gp_file_new_from_fd(&file, fd); 
    if (retval){ 
     // error handling 
    } 

    // copy picture from camera 
    retval = gp_camera_file_get(camera, camera_file_path.folder, camera_file_path.name, GP_FILE_TYPE_NORMAL, file, context); 
    if (retval){ 
     // error handling 
    } 

    // remove picture from camera memory 
    printf("Deleting\n"); 
    retval = gp_camera_file_delete(camera, camera_file_path.folder, camera_file_path.name, context); 
    if (retval){ 
     // error handling 
    } 

    // free CameraFile object 
    gp_file_free(file); 

    // wait till camera is no longer busy, could be done more efficiently (outside this fuction for ex.) 
    int waittime = 2000; 
    CameraEventType type; 
    void *data; 
    printf("Wait for events from camera\n"); 
    while(1){ 
     retval = gp_camera_wait_for_event(camera, waittime, &type, &data, context); 
     if(type == GP_EVENT_TIMEOUT){ 
      break; 
     } 
     else if(type != GP_EVENT_CAPTURE_COMPLETE){ 
      if (type != GP_EVENT_UNKNOWN){ 
       printf("Unexpected event received from camera: %d\n", (int)type); 
      } 
     } 
     else{ 
      break; 
     } 
    } 
    return 0; 
} 


/* 
* This function looks up a label or key entry of 
* a configuration widget. 
* The functions descend recursively, so you can just 
* specify the last component. 
*/ 
static int 
_lookup_widget(CameraWidget*widget, const char *key, CameraWidget **child) { 
    int ret; 
    ret = gp_widget_get_child_by_name (widget, key, child); 
    if (ret < GP_OK) 
     ret = gp_widget_get_child_by_label (widget, key, child); 
    return ret; 
} 

/* Gets a string configuration value. 
* This can be: 
* - A Text widget 
* - The current selection of a Radio Button choice 
* - The current selection of a Menu choice 
* 
* Sample (for Canons eg): 
* get_config_value_string (camera, "owner", &ownerstr, context); 
*/ 
int 
get_config_value_string (const char *key, char **str, GPContext *contxt, Camera *cam) { 
    CameraWidget  *widget = NULL, *child = NULL; 
    CameraWidgetType type; 
    int   ret; 
    char   *val; 

    ret = gp_camera_get_config (cam, &widget, contxt); 
    if (ret < GP_OK) { 
     fprintf (stderr, "camera_get_config failed: %d\n", ret); 
     return ret; 
    } 
    ret = _lookup_widget (widget, key, &child); 
    if (ret < GP_OK) { 
     fprintf (stderr, "lookup widget failed: %d\n", ret); 
     goto out; 
    } 

    /* This type check is optional, if you know what type the label 
    * has already. If you are not sure, better check. */ 
    ret = gp_widget_get_type (child, &type); 
    if (ret < GP_OK) { 
     fprintf (stderr, "widget get type failed: %d\n", ret); 
     goto out; 
    } 
    switch (type) { 
     case GP_WIDGET_MENU: 
     case GP_WIDGET_RADIO: 
     case GP_WIDGET_TEXT: 
     break; 
    default: 
     fprintf (stderr, "widget has bad type %d\n", type); 
     ret = GP_ERROR_BAD_PARAMETERS; 
     goto out; 
    } 

    /* This is the actual query call. Note that we just 
    * a pointer reference to the string, not a copy... */ 
    ret = gp_widget_get_value (child, &val); 
    if (ret < GP_OK) { 
     fprintf (stderr, "could not query widget value: %d\n", ret); 
     goto out; 
    } 
    /* Create a new copy for our caller. */ 
    *str = strdup (val); 
out: 
    gp_widget_free (widget); 
    return ret; 
} 


/* Sets a string configuration value. 
* This can set for: 
* - A Text widget 
* - The current selection of a Radio Button choice 
* - The current selection of a Menu choice 
* 
* Sample (for Canons eg): 
* get_config_value_string (camera, "owner", &ownerstr, context); 
*/ 
int 
set_config_value_string (const char *key, const char *val, GPContext *contxt, Camera *cam) { 
    CameraWidget  *widget = NULL, *child = NULL; 
    CameraWidgetType type; 
    int   ret; 

    ret = gp_camera_get_config (cam, &widget, contxt); 
    if (ret < GP_OK) { 
     fprintf (stderr, "camera_get_config failed: %d\n", ret); 
     return ret; 
    } 
    ret = _lookup_widget (widget, key, &child); 
    if (ret < GP_OK) { 
     fprintf (stderr, "lookup widget failed: %d\n", ret); 
     goto out; 
    } 

    /* This type check is optional, if you know what type the label 
    * has already. If you are not sure, better check. */ 
    ret = gp_widget_get_type (child, &type); 
    if (ret < GP_OK) { 
     fprintf (stderr, "widget get type failed: %d\n", ret); 
     goto out; 
    } 
    switch (type) { 
     case GP_WIDGET_MENU: 
     case GP_WIDGET_RADIO: 
     case GP_WIDGET_TEXT: 
     break; 
    default: 
     fprintf (stderr, "widget has bad type %d\n", type); 
     ret = GP_ERROR_BAD_PARAMETERS; 
     goto out; 
    } 

    /* This is the actual set call. Note that we keep 
    * ownership of the string and have to free it if necessary. 
    */ 
    ret = gp_widget_set_value (child, val); 
    if (ret < GP_OK) { 
     fprintf (stderr, "could not set widget value: %d\n", ret); 
     goto out; 
    } 
    /* This stores it on the camera again */ 
    ret = gp_camera_set_config (cam, widget, contxt); 
    if (ret < GP_OK) { 
     fprintf (stderr, "camera_set_config failed: %d\n", ret); 
     return ret; 
    } 
out: 
    gp_widget_free (widget); 
    return ret; 
} 

void error_func(GPContext *context, const char *format, va_list args, void *data){ 
    fprintf (stderr, "*** Contexterror ***\n"); 
    //fprintf(stderr, format); 
    vfprintf(stderr, format, args); 
    fprintf (stderr, "\n"); 
} 

void message_func(GPContext *context, const char *format, va_list args, void *data){ 
    vprintf(format, args); 
    //fprintf(stderr, format); 
    printf("\n"); 
} 

#endif 

cv_supplement.hpp:

#ifndef CV_SUPPLEMENT 
#define CV_SUPPLEMENT 

#define HEADER_SIZE 23 
#define POS_00 0*img.cols,0 
#define POS_01 1*img.cols,0 
#define POS_02 2*img.cols,0 
#define POS_03 3*img.cols,0 
#define POS_10 0*img.cols, 1*img.rows+2*HEADER_SIZE 
#define POS_11 1*img.cols, 1*img.rows+2*HEADER_SIZE 
#define POS_12 2*img.cols, 1*img.rows+2*HEADER_SIZE 
#define POS_13 3*img.cols, 1*img.rows+2*HEADER_SIZE 
#define POS_20 0*img.cols, 2*img.rows+3*HEADER_SIZE 
#define POS_21 1*img.cols, 2*img.rows+3*HEADER_SIZE 
#define POS_22 2*img.cols, 2*img.rows+3*HEADER_SIZE 
#define POS_23 3*img.cols, 2*img.rows+3*HEADER_SIZE 

#endif 

Итак, как правильно связать две библиотеки? Что я делаю неправильно, или что я пропущу?

спасибо, что заблаговременно!

+0

Если вы обрезаете этот пример до использования только библиотеки gphoto2, это сработает? – jkerian

+0

@jkerian, это именно то, что я только что сделал, и я понял проблему! Спасибо! Проблема была поврежденным файлом FindGphoto2.cmake, который не задавал константы GPHOTO2_INCLUDE_DIR и LIBGPHOTO2_LIBRARIES правильно. Я изменил это, и теперь все работает как исключено :-) –

ответ

1

Я понял, что проблема связана с файлом FindGphoto2.cmake, который я должен был загрузить и включить ранее, чтобы позволить cmake найти путь к библиотеке gphoto2. В этом файле константы GPHOTO2_INCLUDE_DIR и LIBGPHOTO2_LIBRARIES были неправильно настроены, так что библиотека gphoto2 не могла быть связана.

Смежные вопросы