19

I'm writing a program to get myself acquainted with OpenSSL, libncurses, and UDP networking. I decided to work with OpenSSL's SHA256 to become familiar with industry encryption standards, but I'm having issues with getting it working. I've isolated the error to the linking of OpenSSL with the compiled program. I'm working on Ubuntu 12.10, 64 bit. I have the package libssl-dev installed.

Take, for instance, the C++ main.cpp:

#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;

#include <openssl/sha.h>

string sha256(const string str)
{
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, str.c_str(), str.size());
    SHA256_Final(hash, &sha256);
    stringstream ss;
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        ss << hex << setw(2) << setfill('0') << (int)hash[i];
    }
    return ss.str();
}

int main()
{

    cout << sha256("test") << endl;
    cout << sha256("test2") << endl;

    return 0;

}

I'm using the SHA256() function found here as a wrapper for OpenSSL's SHA256 functionality.

When I attempt to compile with the following g++ arguments, I receive the following error:

millinon@myhost:~/Programming/sha256$ g++ -lssl -lcrypto -o main main.cpp
/tmp/ccYqwPUC.o: In function `sha256(std::string)':
main.cpp:(.text+0x38): undefined reference to `SHA256_Init'
main.cpp:(.text+0x71): undefined reference to `SHA256_Update'
main.cpp:(.text+0x87): undefined reference to `SHA256_Final'
collect2: error: ld returned 1 exit status

So, GCC clearly recognizes OpenSSL's defined functions and types, but ld is failing to find the function symbols referred to in sha.h.

Do I need to manually point to a specific shared object or directory?

Thanks!

jww
  • 97,681
  • 90
  • 411
  • 885
millinon
  • 1,528
  • 1
  • 20
  • 31

2 Answers2

36

You make a very common beginners mistake... Putting the libraries you link with in the wrong place on the command line when you build.

Dependencies are reversed on the command line, so something that depends on something else should actually be put before what it depends on on the command line.

In your example, you have a source file main.cpp that depends on some set of libraries, then the source file should be before the libraries it depend on:

$ g++ -o main main.cpp -lssl -lcrypto

To be safe, always put libraries last, after any source or object files listed on the command line.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • By golly, it worked! Thanks! I've used GCC for about 7 years for minor things, but I never realized that command line arguments worked like that. – millinon Dec 09 '12 at 05:13
  • 2
    after the `-o main` is enough. very few Unix programs require you to put options after arguments, and in general it's a bad practice IMO. – jcomeau_ictx Jul 09 '13 at 04:03
  • 3
    @jcomeau_ictx: Huh? No, that's not enough. It should go after the source files that reference the symbols in those libraries. i.e. "after the `main.cpp` is enough". – Lightness Races in Orbit Sep 05 '14 at 15:24
-1

This works fine on my system, but you might try:

extern "C" {
#include <openssl/sha.h>
}

which tells g++ that all the stuff in openssl/sha.h is declared as "C" functions.

BTW, how old is your OpenSSL?

Marshall Clow
  • 15,972
  • 2
  • 29
  • 45
  • I tried that, and using my above GCC arguments, I still received the same errors. Joachim's suggestion fixed it. I'm using OpenSSL version 1.0.1c, for the record. – millinon Dec 09 '12 at 05:16