2

I've got a simple C++ project set up that I'm trying to compile with CMake, and I'm trying to statically link libcurl to it. In my main.cpp I've got the standard curl_easy_init example code, and I'm trying just to send a simple request to make sure the library is working. However, I'm getting undefined reference errors on every cURL function call. In my CMakeLists.txt I'm checking for the current platform, then linking the right libraries from that specific if statement. My error log, main.cpp, and CMakeLists.txt are below. My only question is how do I get my libcurl to link properly, as I don't think it is now, because my binary is only 72KB when I can actually get it to compile removing the cURL specific code but leaving the header file. Other than the obvious, one thing I've tried is using is the --enable-stdcall-fixup linker flag, which did not work at all.

Error Log:

C:\Users\bfsco\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\163.13906.4\bin\cmake\bin\cmake.exe --build D:\Programming\CPP\cppackage\cmake-build-debug --target all -- -j 4
[ 50%] Linking CXX executable cppackage.exe
CMakeFiles\cppackage.dir/objects.a(main.cpp.obj): In function `main':
D:/Programming/CPP/cppackage/main.cpp:6: undefined reference to `curl_easy_init'
D:/Programming/CPP/cppackage/main.cpp:10: undefined reference to `curl_easy_setopt'
D:/Programming/CPP/cppackage/main.cpp:11: undefined reference to `curl_easy_perform'
D:/Programming/CPP/cppackage/main.cpp:13: undefined reference to `curl_easy_cleanup'
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe[2]: *** [cppackage.exe] Error 1
CMakeFiles\cppackage.dir\build.make:98: recipe for target 'cppackage.exe' failed
mingw32-make.exe[1]: *** [CMakeFiles/cppackage.dir/all] Error 2
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/cppackage.dir/all' failed
mingw32-make.exe: *** [all] Error 2
Makefile:82: recipe for target 'all' failed

main.cpp:

#include <iostream>

#include "include/curl/curl.h"

int main() {
    CURL *curl = curl_easy_init();

    if(curl) {
        CURLcode res;
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
        res = curl_easy_perform(curl);
        std::cout << res << std::endl;
        curl_easy_cleanup(curl);
    }

    std::cout << "Hello, World!" << std::endl;
    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.6)
project(cppackage)

set(CMAKE_CXX_STANDARD 14)
set(SOURCE_FILES main.cpp)

include_directories(${CMAKE_SOURCE_DIR}/include/curl)

add_executable(${PROJECT_NAME} ${SOURCE_FILES})

if(WIN32)
    add_definitions(-DCURL_STATICLIB)
    target_link_libraries(cppackage ${CMAKE_SOURCE_DIR}/thirdparty/openssl/openssl.lib ${CMAKE_SOURCE_DIR}/thirdparty/curl/libcurl.lib)
else()
    target_link_libraries(cppackage ${CMAKE_SOURCE_DIR}/thirdparty/curl/libcurl.a)
endif()
Wargog
  • 398
  • 1
  • 3
  • 13

2 Answers2

1

It seems you are trying to link a library built from Visual Studio to an application built with MinGW. This is normally not possible. You should try to build libcurl from source with MinGW.


Original answer:

Try separating the 2 library versions in 2 different directories /thirdparty/curl_win32 and /thirdparty/curl_2, and then to change your code into:

if(WIN32)
    add_definitions(-DCURL_STATICLIB)
    link_directories("${CMAKE_SOURCE_DIR}/thirdparty/openssl/" "${CMAKE_SOURCE_DIR}/thirdparty/"curl_win32)
else()
    link_directories("${CMAKE_SOURCE_DIR}/thirdparty/curl2")
endif()

add_executable(${PROJECT_NAME} ${SOURCE_FILES})

if(WIN32)
    target_link_libraries(${PROJECT_NAME} openssl curl)
else()
    target_link_libraries(${PROJECT_NAME} curl)
endif()

Note that apparently the link_directories command must come before the add_executable command. See here.

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
  • Using that results in this error: C:\Users\bfsco\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\163.13906.4\bin\cmake\bin\cmake.exe --build D:\Programming\CPP\cppackage\cmake-build-debug --target all -- -j 4 [ 50%] Linking CXX executable cppackage.exe c:/binaries/mingw/bin/../lib/gcc/mingw32/5.3.0/../../../../mingw32/bin/ld.exe: cannot find -lopenssl c:/binaries/mingw/bin/../lib/gcc/mingw32/5.3.0/../../../../mingw32/bin/ld.exe: cannot find -lcurl collect2.exe: error: ld returned 1 exit status – Wargog Mar 08 '17 at 14:45
  • @Wargog Do you actually have the library in this location? ${CMAKE_SOURCE_DIR}/thirdparty/curl_win32 ... And, check output by adding VERBOSE=1 to your command line – Antonio Mar 08 '17 at 14:48
  • OK, I've actually got it to go past the cannot find package to link, I'm still getting the reference not found error. Here's my current CMakeLists.txt: http://pastebin.com/CEi8q6JF – Wargog Mar 08 '17 at 15:15
  • Check if you actually have the symbols in your third party library http://stackoverflow.com/questions/305287/how-to-see-the-contents-of-windows-library-lib – Antonio Mar 08 '17 at 15:54
  • From here: https://github.com/peters/curl-for-windows. I downloaded the x64 binary package from the Sourceforge link. Also DUMPBIN /SYMBOLS returns this: http://pastebin.com/qmdjgxrF – Wargog Mar 08 '17 at 16:05
  • @Wargog That's the problem: you downloaded the 64bit packages, but you are building a 32bit application, i.e. using mingw32. Also, the `dumpbin` output seems incomplete, maybe try `dumpbin /all ` – Antonio Mar 08 '17 at 16:32
  • Here is the output of the dumpbin /all: http://pastebin.com/yQj6C0Ac. Using the 32bit library gives me this error, but I think it's an error with the packaging of the library: D:/Programming/CPP/cppackage/thirdparty/curl/libcurl.x86.lib: error adding symbols: File format not recognized – Wargog Mar 08 '17 at 17:08
  • @Wargog That should be the error you get when you mix 32 with 64bit, so it seems you are building a 64bit binary after all. I think you should forget cmake for the moment, and find first of all the linker command line that would allow the linking to succeed. I suspect the point is that libcurl was built with Visual Studio (see https://winampplugins.co.uk/curl/), while you are building with MinGW. I guess you will have to recompile libcurl form source. See also: http://www.mingw.org/wiki/Interoperability_of_Libraries_Created_by_Different_Compiler_Brands – Antonio Mar 09 '17 at 09:20
0

Personnally, I always use command "set" for librairies which I pass the relative path and then put that variable in the target_link_libraries.

Zethzer
  • 59
  • 1
  • 7
  • The way I understand it is that if it's a compiled library, which mine are, it has to be an explicit path to the library (Which in my case is a .lib file, or a .a or .o file), not a path. I'm pretty sure using a path means that you're trying to compile the library in that location, which I'm not. – Wargog Mar 08 '17 at 04:57
  • Mh... Sorry I put you an exemple : set(CURL_LIB ${CMAKE_SOURCE_DIR}/thirdparty/curl/libcurl.lib) and use the variable &{CURL_LIB} in the target_link_libraries command. I have the same needs for a project (just not the same lib) and I do that on 3 platform (and pass the right lib of course) – Zethzer Mar 08 '17 at 04:58