Cannot link curl library to project

Hello,

I am building a C++ program which needs to send information to an FTP server with the help of curl library. For the purpose I have created a docker image and a program with the help of ApolloX on VS Code for Apalis iMX6 board.
This is the code that I am using:

#include <iostream>
#include <curl/curl.h>

int ftpConnect(const char* server, const char* username, const char* password) {
    CURL* curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, server);
        curl_easy_setopt(curl, CURLOPT_USERPWD, (std::string(username) + ":" + std::string(password)).c_str());
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 0L);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            std::cerr << "Failed to connect to FTP server: " << curl_easy_strerror(res) << std::endl;
            curl_easy_cleanup(curl);
            return 1;
        }
        curl_easy_cleanup(curl);
        std::cout << "Connected to FTP server successfully." << std::endl;
        return 0;
    }
    return 1;
}
 
int ftpUpload(const char* server, const char* username, const char* password, const char* filePath) {
    CURL* curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, server);
        curl_easy_setopt(curl, CURLOPT_USERPWD, (std::string(username) + ":" + std::string(password)).c_str());
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
        curl_easy_setopt(curl, CURLOPT_READDATA, fopen(filePath, "rb"));
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            std::cerr << "Failed to upload file: " << curl_easy_strerror(res) << std::endl;
            curl_easy_cleanup(curl);
            return 1;
        }
        curl_easy_cleanup(curl);
        std::cout << "File uploaded successfully." << std::endl;
        return 0;
    }
    return 1;
}
int main() {
    const char* server = "10.58.63.175";
    const char* username = "Torizon";
    const char* password = "69";
    const char* filePath = "/media/card/2023-04-14.txt";
 
    // Connect to FTP server
    int connectResult = ftpConnect(server, username, password);
    if (connectResult != 0) {
        std::cerr << "Failed to connect to FTP server." << std::endl;
        return 1;
    }
 
    // Upload file to FTP server
    int uploadResult = ftpUpload(server, username, password, filePath);
    if (uploadResult != 0) {
        std::cerr << "Failed to upload file to FTP server." << std::endl;
        return 1;
    }
    return 0;
}


The problem is I can’t link the library to the docker image apparently.
In the Dockerfile.sdk I have included libcurl4-gnutls-dev so it is installed in my docker container.
When I do just this, I get the following error:

app/src/internet_manager.cpp:38: undefined reference to `curl_easy_cleanup'
collect2: error: ld returned 1 exit status
make: *** [Makefile:47: armhf/debug/pesho] Error 1

But if I do not include this then the code crashed on the #include of the library. So that would tell me that after using this command I successfully install curl on the docker image.

From what I saw on the internet this is a problem for not linking curl so I tried to link it in the Makefile the following ways:

LDFLAGS :=  -lcurl
LDFLAGS := -L/usr/lib/arm-linux-gnueabihf/  -lcurl
LDFLAGS := -L/usr/lib/x86_64-linux-gnu/
LDFLAGS := -L/usr/bin/curl -lcurl

For the paths for curl in the docker image and in the WSL2 ubuntu system that I use. All of them get this error:
*

bug/main.o -o armhf/debug/pesho -L/usr/lib/arm-linux-gnueabihf/  -lcurl
/usr/lib/gcc-cross/arm-linux-gnueabihf/10/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lcurl
collect2: error: ld returned 1 exit status
make: *** [Makefile:47: armhf/debug/pesho] Error 1

The weird part is I have checked curl and it is installed both on the host machine and in the Debian based docker container that the program is running on.

What a colleague of mine try to do is run curl locally in the src file to see if it is accessible in there and he was not able to run it.

These are the docker images I have:


Where the first one, pesho-debeliq-debug is the used container.

My colleague has a suspicion that curl is not available on the debian-cross-toolchain-ssh-arm64 which should be the container to link the code.
And we are wondering if we should link the curl there somehow or add curl library to this container as well in order to work.
Or are we doing something wrong in these configurations to be missing something?

Greetings @Svetoslav

I copied your code and created a new ApolloX project on my setup. All I did was add the appropriate curl library package to the SDK and then added the libcurl link in the Makefile (-lcurl). Once I did that I ran the build command and it was successful and a compiled binary was produced from your code.

Therefore I would assume it’s a configuration issue with your project. Could you please share the contents of the following files in your project:

  • torizonPackages.json
  • Dockerfile.sdk
  • Dockerfile.debug

Let’s see if we can narrow down what the issue is on your setup.

Best Regards,
Jeremias

Here are the files requested:
torizonPackages.json:

{
    "deps": [
    ],
    "devDeps": [
    ]
}

Dockerfile.sdk:

# ARGUMENTS --------------------------------------------------------------------
ARG CROSS_SDK_BASE_TAG=2.7-bullseye

##
# Board architecture
# arm or arm64
##
ARG IMAGE_ARCH=


# BUILD ------------------------------------------------------------------------
FROM torizon/debian-cross-toolchain-${IMAGE_ARCH}:${CROSS_SDK_BASE_TAG}

# __deps__
RUN apt-get -q -y update && \
    apt-get -q -y install \
    # ADD YOUR PACKAGES HERE
    libcurl4-gnutls-dev \
    ntp \
    && \
    apt-get clean && apt-get autoremove && \
    rm -rf /var/lib/apt/lists/*
# __deps__

# automate for torizonPackages.json
RUN apt-get -q -y update && \
    apt-get -q -y install \
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
    # __torizon_packages_dev_start__
    # __torizon_packages_dev_end__
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
    && \
    apt-get clean && apt-get autoremove && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app

Dockerfile.debug:

# ARGUMENTS --------------------------------------------------------------------
##
# Board architecture
##
ARG IMAGE_ARCH=
# For armv7 use:
#ARG IMAGE_ARCH=arm

##
# Base container version
##
ARG BASE_VERSION=2.5-bullseye

##
# Application Name
##
ARG APP_EXECUTABLE=app

##
# Debug port
##
ARG SSH_DEBUG_PORT=

##
# Run as
##
ARG SSHUSERNAME=

# BUILD ------------------------------------------------------------------------
##
# Deploy Step
##
FROM --platform=linux/${IMAGE_ARCH} \
    torizonextras/debian:${BASE_VERSION} AS Debug

ARG IMAGE_ARCH
ARG SSH_DEBUG_PORT
ARG APP_EXECUTABLE
ARG SSHUSERNAME
ENV APP_EXECUTABLE ${APP_EXECUTABLE}

# SSH for remote debug
EXPOSE ${SSH_DEBUG_PORT}

# Make sure we don't get notifications we can't answer during building.
ENV DEBIAN_FRONTEND="noninteractive"

# your regular RUN statements here
# Install required packages
RUN apt-get -q -y update && \
    apt-get -q -y install \
    openssl \
    openssh-server \
    rsync \
    file \
    curl \
    libcurl4-gnutls-dev \
    gdb && \
    apt-get clean && apt-get autoremove && \
    rm -rf /var/lib/apt/lists/*

# automate for torizonPackages.json
RUN apt-get -q -y update && \
    apt-get -q -y install \
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
    # __torizon_packages_dev_start__
    # __torizon_packages_dev_end__
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
    && \
    apt-get clean && apt-get autoremove && \
    rm -rf /var/lib/apt/lists/*

# ⚠️ DEBUG PURPOSES ONLY!!
# copies RSA key to enable SSH login for user
COPY .conf/id_rsa.pub /id_rsa.pub

# create folders needed for the different components
# configures SSH access to the container and sets environment by default
RUN mkdir /var/run/sshd && \
    sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' \
        -i /etc/pam.d/sshd && \
    if test $SSHUSERNAME != root ; \
        then mkdir -p /home/$SSHUSERNAME/.ssh ; \
        else mkdir -p /root/.ssh ; fi && \
    if test $SSHUSERNAME != root ; \
        then cp /id_rsa.pub /home/$SSHUSERNAME/.ssh/authorized_keys ; \
        else cp /id_rsa.pub /root/.ssh/authorized_keys ; fi && \
    echo "PermitUserEnvironment yes" >> /etc/ssh/sshd_config && \
    echo "Port ${SSH_DEBUG_PORT}" >> /etc/ssh/sshd_config && \
    su -c "env" $SSHUSERNAME > /etc/environment

RUN rm -r /etc/ssh/ssh*key && \
    dpkg-reconfigure openssh-server

CMD [ "/usr/sbin/sshd", "-D" ]

I think I see the issue now on your side. You installed the curl development libraries in the SDK container with libcurl4-gnutls-dev, which is correct. However, the SDK container has an x86 architecture, meaning when you install packages in this container it installs the x86 version of that package. To install another architecture of a package you need to specify like libcurl4-gnutls-dev:armhf (this is for arm32). At least this is what I have on my side, I used the openssl variant of libcurl but the same thing should apply here.

Basically you were trying to link an x86 library to compile arm32 code.

Best Regards,
Jeremias

1 Like

Thank you, that solved the problem.

Glad I could help clear things up.

1 Like