我想用CMake
这个简单的tesseract C++ 代码进行编译和构建:
// https://tesseract-ocr.github.io/tessdoc/Examples_C++.html
#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>
int main()
{
char *outText;
tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();
// Initialize tesseract-ocr with English, without specifying tessdata path
if (api->Init(NULL, "eng")) {
fprintf(stderr, "Could not initialize tesseract.\n");
exit(1);
}
// Open input image with leptonica library
Pix *image = pixRead("phototest.tif");
api->SetImage(image);
// Get OCR result
outText = api->GetUTF8Text();
printf("OCR output:\n%s", outText);
// Destroy used object and release memory
api->End();
delete api;
delete [] outText;
pixDestroy(&image);
return 0;
}
有了这个CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.5)
project(BasicExample)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(tesseract REQUIRED IMPORTED_TARGET tesseract)
pkg_check_modules(leptonica REQUIRED IMPORTED_TARGET lept)
pkg_check_moduleS(libcurl REQUIRED IMPORTED_TARGET libcurl)
add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE BasicExample.cpp)
target_link_libraries(BasicExample PUBLIC
PkgConfig::leptonica
PkgConfig::tesseract
-lcurl
)
我收到这些错误:
raphy@raohy:~/tesseract/Examples$ cmake -B builddir
-- The C compiler identification is GNU 12.3.0
-- The CXX compiler identification is GNU 13.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "1.8.1")
-- Checking for module 'tesseract'
-- Found tesseract, version 5.3.4
-- Checking for module 'lept'
-- Found lept, version 1.82.0
-- Checking for module 'libcurl'
-- Found libcurl, version 8.2.1
-- Configuring done (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/raphy/tesseract/Examples/builddir
raphy@raohy:~/tesseract/Examples$
raphy@raohy:~/tesseract/Examples$ cmake --build builddir/
[ 50%] Building CXX object CMakeFiles/BasicExample.dir/BasicExample.cpp.o
[100%] Linking CXX executable BasicExample
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o): in function `tesseract::TessBaseAPI::ProcessPagesInternal(char const*, char const*, int, tesseract::TessResultRenderer*)::{lambda(char const*)#1}::operator()(char const*) const':
baseapi.cpp:(.text+0x13): undefined reference to `curl_easy_strerror'
/usr/bin/ld: baseapi.cpp:(.text+0x3b): undefined reference to `curl_easy_cleanup'
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o): in function `tesseract::TessBaseAPI::ProcessPagesInternal(char const*, char const*, int, tesseract::TessResultRenderer*)':
baseapi.cpp:(.text+0xad07): undefined reference to `curl_easy_init'
/usr/bin/ld: baseapi.cpp:(.text+0xad48): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xad5d): undefined reference to `curl_easy_strerror'
/usr/bin/ld: baseapi.cpp:(.text+0xad89): undefined reference to `curl_easy_cleanup'
/usr/bin/ld: baseapi.cpp:(.text+0xb26f): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb298): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb2c1): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb2fa): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb324): undefined reference to `curl_easy_setopt'
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o):baseapi.cpp:(.text+0xb3c9): more undefined references to `curl_easy_setopt' follow
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o): in function `tesseract::TessBaseAPI::ProcessPagesInternal(char const*, char const*, int, tesseract::TessResultRenderer*)':
baseapi.cpp:(.text+0xb455): undefined reference to `curl_easy_perform'
/usr/bin/ld: baseapi.cpp:(.text+0xb6b0): undefined reference to `curl_easy_cleanup'
/usr/bin/ld: /usr/local/lib/libtesseract.a(tessdatamanager.cpp.o): in function `tesseract::TessdataManager::LoadArchiveFile(char const*)':
tessdatamanager.cpp:(.text+0x199): undefined reference to `archive_read_new'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1ad): undefined reference to `archive_read_support_filter_all'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1b5): undefined reference to `archive_read_support_format_all'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1c5): undefined reference to `archive_read_open_filename'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1e6): undefined reference to `archive_entry_pathname'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1f6): undefined reference to `archive_read_next_header'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x208): undefined reference to `archive_read_free'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x294): undefined reference to `archive_entry_size'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x2e1): undefined reference to `archive_read_data'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/BasicExample.dir/build.make:99: BasicExample] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/BasicExample.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2
但是这个 CMakeLists.txt :
# https://stackoverflow.com/questions/28165518/use-libcurl-undefined-reference-to-curl-easy-init
cmake_minimum_required(VERSION 3.5)
project(Url2File)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(libcurl REQUIRED IMPORTED_TARGET libcurl)
add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE url2file.c)
target_link_libraries(${PROJECT_NAME} PUBLIC
-lcurl
)
对于这个 libcurl 用法示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <curl/curl.h>
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
return written;
}
int main(int argc, char *argv[])
{
CURL *curl_handle;
static const char *pagefilename = "page.out";
FILE *pagefile;
if(argc < 2) {
printf("Usage: %s <URL>\n", argv[0]);
return 1;
}
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* set URL to get here */
curl_easy_setopt(curl_handle, CURLOPT_URL, argv[1]);
/* Switch on full protocol/debug output while testing */
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
/* disable progress meter, set to 0L to enable it */
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
/* open the file */
pagefile = fopen(pagefilename, "wb");
if(pagefile) {
/* write the page body to this file handle */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);
/* get it! */
curl_easy_perform(curl_handle);
/* close the header file */
fclose(pagefile);
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return 0;
}
工作正常 :
raphy@raohy:~/curlExample$ cmake --build builddir/
[ 50%] Building C object CMakeFiles/Url2File.dir/url2file.c.o
[100%] Linking C executable Url2File
[100%] Built target Url2File
更新1)
我尝试仅保留 lcurl 作为 target_link_libraries:
target_link_libraries(BasicExample PUBLIC
#PkgConfig::leptonica
#PkgConfig::tesseract
-lcurl
)
实际上,有关 libcurl 的错误消失了:
raphy@raohy:~/tesseract/Examples$ cmake --build builddir/
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/raphy/tesseract/Examples/builddir
[ 50%] Building CXX object CMakeFiles/BasicExample.dir/BasicExample.cpp.o
[100%] Linking CXX executable BasicExample
/usr/bin/ld: CMakeFiles/BasicExample.dir/BasicExample.cpp.o: in function `main':
BasicExample.cpp:(.text+0x37): undefined reference to `tesseract::TessBaseAPI::TessBaseAPI()'
/usr/bin/ld: BasicExample.cpp:(.text+0x98): undefined reference to `pixRead'
/usr/bin/ld: BasicExample.cpp:(.text+0xaf): undefined reference to `tesseract::TessBaseAPI::SetImage(Pix*)'
/usr/bin/ld: BasicExample.cpp:(.text+0xbb): undefined reference to `tesseract::TessBaseAPI::GetUTF8Text()'
/usr/bin/ld: BasicExample.cpp:(.text+0xe6): undefined reference to `tesseract::TessBaseAPI::End()'
/usr/bin/ld: BasicExample.cpp:(.text+0x11d): undefined reference to `pixDestroy'
/usr/bin/ld: CMakeFiles/BasicExample.dir/BasicExample.cpp.o: in function `tesseract::TessBaseAPI::Init(char const*, char const*)':
BasicExample.cpp:(.text._ZN9tesseract11TessBaseAPI4InitEPKcS2_[_ZN9tesseract11TessBaseAPI4InitEPKcS2_]+0x43): undefined reference to `tesseract::TessBaseAPI::Init(char const*, char const*, tesseract::OcrEngineMode, char**, int, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const*, bool)'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/BasicExample.dir/build.make:97: BasicExample] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/BasicExample.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2
但是得到了 tesseract 和 leptonica 的链接错误
基于这篇文章的答案:Use libcurl undefined reference to 'curl_easy_init' , -lcurl
has to be put in the end of gcc command 。那么...如何正确链接它们呢?
有了这个CmakeLists.txt
:
cmake_minimum_required(VERSION 3.5)
project(BasicExample)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(tesseract REQUIRED IMPORTED_TARGET tesseract)
pkg_check_modules(leptonica REQUIRED IMPORTED_TARGET lept)
pkg_check_moduleS(libcurl REQUIRED IMPORTED_TARGET libcurl)
add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE BasicExample.cpp)
target_link_libraries(BasicExample PUBLIC
PkgConfig::leptonica
PkgConfig::tesseract
-lcurl
)
这是以下的输出/builddir$ make VERBOSE=1
:
raphy@raohy:~/tesseract/Examples/builddir$ make VERBOSE=1
/usr/local/bin/cmake -S/home/raphy/tesseract/Examples -B/home/raphy/tesseract/Examples/builddir --check-build-system CMakeFiles/Makefile.cmake 0
/usr/local/bin/cmake -E cmake_progress_start /home/raphy/tesseract/Examples/builddir/CMakeFiles /home/raphy/tesseract/Examples/builddir//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/raphy/tesseract/Examples/builddir'
make -f CMakeFiles/BasicExample.dir/build.make CMakeFiles/BasicExample.dir/depend
make[2]: Entering directory '/home/raphy/tesseract/Examples/builddir'
cd /home/raphy/tesseract/Examples/builddir && /usr/local/bin/cmake -E cmake_depends "Unix Makefiles" /home/raphy/tesseract/Examples /home/raphy/tesseract/Examples /home/raphy/tesseract/Examples/builddir /home/raphy/tesseract/Examples/builddir /home/raphy/tesseract/Examples/builddir/CMakeFiles/BasicExample.dir/DependInfo.cmake "--color="
Dependencies file "CMakeFiles/BasicExample.dir/BasicExample.cpp.o.d" is newer than depends file "/home/raphy/tesseract/Examples/builddir/CMakeFiles/BasicExample.dir/compiler_depend.internal".
Consolidate compiler generated dependencies of target BasicExample
make[2]: Leaving directory '/home/raphy/tesseract/Examples/builddir'
make -f CMakeFiles/BasicExample.dir/build.make CMakeFiles/BasicExample.dir/build
make[2]: Entering directory '/home/raphy/tesseract/Examples/builddir'
[ 50%] Linking CXX executable BasicExample
/usr/local/bin/cmake -E cmake_link_script CMakeFiles/BasicExample.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/BasicExample.dir/BasicExample.cpp.o -o BasicExample -lcurl /usr/lib/x86_64-linux-gnu/liblept.so /usr/local/lib/libtesseract.a
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o): in function `tesseract::TessBaseAPI::ProcessPagesInternal(char const*, char const*, int, tesseract::TessResultRenderer*)::{lambda(char const*)#1}::operator()(char const*) const':
baseapi.cpp:(.text+0x13): undefined reference to `curl_easy_strerror'
/usr/bin/ld: baseapi.cpp:(.text+0x3b): undefined reference to `curl_easy_cleanup'
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o): in function `tesseract::TessBaseAPI::ProcessPagesInternal(char const*, char const*, int, tesseract::TessResultRenderer*)':
baseapi.cpp:(.text+0xad07): undefined reference to `curl_easy_init'
/usr/bin/ld: baseapi.cpp:(.text+0xad48): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xad5d): undefined reference to `curl_easy_strerror'
/usr/bin/ld: baseapi.cpp:(.text+0xad89): undefined reference to `curl_easy_cleanup'
/usr/bin/ld: baseapi.cpp:(.text+0xb26f): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb298): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb2c1): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb2fa): undefined reference to `curl_easy_setopt'
/usr/bin/ld: baseapi.cpp:(.text+0xb324): undefined reference to `curl_easy_setopt'
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o):baseapi.cpp:(.text+0xb3c9): more undefined references to `curl_easy_setopt' follow
/usr/bin/ld: /usr/local/lib/libtesseract.a(baseapi.cpp.o): in function `tesseract::TessBaseAPI::ProcessPagesInternal(char const*, char const*, int, tesseract::TessResultRenderer*)':
baseapi.cpp:(.text+0xb455): undefined reference to `curl_easy_perform'
/usr/bin/ld: baseapi.cpp:(.text+0xb6b0): undefined reference to `curl_easy_cleanup'
/usr/bin/ld: /usr/local/lib/libtesseract.a(tessdatamanager.cpp.o): in function `tesseract::TessdataManager::LoadArchiveFile(char const*)':
tessdatamanager.cpp:(.text+0x199): undefined reference to `archive_read_new'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1ad): undefined reference to `archive_read_support_filter_all'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1b5): undefined reference to `archive_read_support_format_all'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1c5): undefined reference to `archive_read_open_filename'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1e6): undefined reference to `archive_entry_pathname'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x1f6): undefined reference to `archive_read_next_header'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x208): undefined reference to `archive_read_free'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x294): undefined reference to `archive_entry_size'
/usr/bin/ld: tessdatamanager.cpp:(.text+0x2e1): undefined reference to `archive_read_data'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/BasicExample.dir/build.make:99: BasicExample] Error 1
make[2]: Leaving directory '/home/raphy/tesseract/Examples/builddir'
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/BasicExample.dir/all] Error 2
make[1]: Leaving directory '/home/raphy/tesseract/Examples/builddir'
make: *** [Makefile:91: all] Error 2
raphy@raohy:~/tesseract/Examples/builddir$
我缺少什么?如何使 CMakeLists.txt 适用于 tesseract C++ 代码示例?
这是
tesseract
需要的图书馆curl
。因为PkgConfig::tesseract
是一个 INTERFACE 库,所以您可以通过附加到其 INTERFACE_LINK_LIBRARIES 属性来告诉 CMake 该依赖关系:上述方法依赖于模块FindPkgConfig.cmake实际为 IMPORTED_TARGET 选项创建目标的方式。因此,该方法适用于通过 获取的其他静态库
pkg_check_modules(... IMPORTED_TARGET)
,但对于通过其他方式获取的库可能会失败。细节
正如您从 VERBOSE 输出中看到的,您的链接
curl
位于的链接之前tesseract
。这就是“未定义引用”错误的原因:它是使用curl的tesseract库,并且为了正确解析该链接curl
应该出现在tesseract
.通常,CMake 会保留命令中指定的库的顺序
target_link_libraries
,因此使用以下行人们期望 CMake 能够与
curl
所有其他库建立链接。不幸的是,它
PkgConfig::tesseract
实际上是一个 INTERFACE 库,它本身并不引用 tesseract,而是将其包含在其INTERFACE_LINK_LIBRARIES 属性中。当形成链接器的命令行时,CMake 会在 的所有“直接”操作数之后添加该属性的值target_link_libraries
。这就是为什么 CMakecurl
放在tesseract
.通过建议的方法, 和 都
tesseract
成为curl
单个属性的一部分INTERFACE_LINK_LIBRARIES
,因此 CMake 在创建链接器的命令行时保留它们的顺序。