uriparser / uriparser

:hocho: Strictly RFC 3986 compliant URI parsing and handling library written in C89; moved from SourceForge to GitHub

Home Page:https://uriparser.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

undefined reference for some exposed functions

tregua87 opened this issue · comments

I am playing with the library. But I have some trouble to statically (and dynamically) link some functions.

For some reasons, there are some functions that seem to be exposed but I can't link to my binary, such as the function uriEmulateCalloc. I am interested in the static library. But I observed the same behavior with the dynamic one too.

I use the streamline version of uriparser, and I compile in this way.

cmake  -DCMAKE_INSTALL_PREFIX=${WORK} -DCMAKE_BUILD_TYPE=Release -DURIPARSER_BUILD_DOCS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF -DURIPARSER_BUILD_TESTS:BOOL=OFF        
make -j$(nproc) clean
make -j$(nproc)
make install

the folders $WORK/{include, lib} contain the header files and liburiparser.a, respectively.

Then I try to link against this minimal example, main.c:

#include <uriparser/UriDefsConfig.h>
#include <uriparser/UriBase.h>
#include <uriparser/UriDefsAnsi.h>
#include <uriparser/UriDefsUnicode.h>
#include <uriparser/UriIp4.h>
#include <uriparser/Uri.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <stdint.h>

int main(int argc, char** argv) {

    int s0 = 0xA;
    int s1 = 0xB;

    UriMemoryManager UriMemoryManager_p_s0;	
	uriEmulateCalloc(&UriMemoryManager_p_s0, s0, s1);

	return 0;
}

and finally compile main.c against liburiparser.a as following:

CXX=$LLVM_DIR/bin/clang++
$CXX -std=c++11 -I${WORK}/include main.c ${WORK}/lib/liburiparser.a -o main

and obtain

/usr/bin/ld: /tmp/main-c41907.o: in function `main':
main.c:(.text+0x31): undefined reference to `uriEmulateCalloc(UriMemoryManagerStruct*, unsigned long, unsigned long)'
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)

However, the library liburiparser.a contains a reference to uriEmulateCalloc.
uriEmulateCalloc seems similar to other functions, that I can normally use. See this example for uriParseUriA.
Both uriEmulateCalloc and uriParseUriA seem correct exposed symbols, but I can only link against uriParseUriA.

$ nm -A liburiparser.a | grep uriParseUriA              
liburiparser.a:UriParse.c.o:0000000000000aa0 T uriParseUriA
$ nm -A liburiparser.a | grep uriEmulateCalloc
liburiparser.a:UriMemory.c.o:0000000000000030 T uriEmulateCalloc

Do you have any clue why I cannot link uriEmulateCalloc?

Hi @tregua87 from a first quick look, two things catch my eye:

  • For uriparser, #include <uriparser/Uri.h> should be the only include you need. In particular UriDefsAnsi.h is more of an internal header and should not be included directly. Same for the Unicode one.
  • C++ is not a true superset of C for all pairs of versions, please compile the code as C89, not as C++11.

My guess is that the former — dropping all Uriparser includes but the main one — will already fix this problem. Let's see, please let me know if it did.

thanks @hartwork !

Actually, leaving only #include <uriparser/Uri.h> solves my problem. I can compile!
I did not have to compile as C89, C++11 worked already.

I have one, maybe naive, question. After make install, I assumed all the headers exported in ./include are meant to be imported in the client. Why do you export headers that are useful only for internal development?

Actually, leaving only #include <uriparser/Uri.h> solves my problem. I can compile!

@tregua87 cool!

I did not have to compile as C89, C++11 worked already.

Nice, but not recommend. I have had repeated reports on libexpat where people were compiling C code as C++ and else all would have been just fine. So that's why it felt like worth mentioning. It prevents future waste of time for everyone.

I have one, maybe naive, question. After make install, I assumed all the headers exported in ./include are meant to be imported in the client. Why do you export headers that are useful only for internal development?

These headers are internal in the sense that the user should not include them directly but public in the sense that they are needed installed alongside the others for uriparser to work properly. What's happening there is arguably a but crazy: Code is including itself twice using the preprocessor at compile time with different configuration which allows uriparser code to effectively generate code for char and wchar_t from a single implementation without duplication. That "magic" affects both interface and implementation.

Should I close the ticket?

Thanks for the reply.

Please close the issue.

@ffontaine glad I could help, will do 👍