Thread overview
ImportC linking issue
Nov 11, 2022
confuzzled
Nov 12, 2022
confuzzled
Nov 12, 2022
Mike Parker
Nov 12, 2022
confuzzled
Nov 12, 2022
Mike Parker
Nov 12, 2022
confuzzled
Nov 12, 2022
confuzzled
Nov 13, 2022
Andrey Zherikov
November 11, 2022

Wondering if someone can help me with this. Mr. Adam D. Ruppe got me 90% there, but I'm a little lost after reaching the 99% mark. I want to use XLSX I/O to manipulate excel spreadsheets.

I've cloned, built, and installed the library. And with the help of Adam, I am now able to import it and link to D program (as long as I'm not using anything from the lib). Wanted to continue the discussion with Adam, but I realize the announce forum isn't the place to ask for help.

Anyway, the library has two dependencies:

  • expat (only for libxlsxio_read)
  • minizip or libzip (libxlsxio_read and libxlsxio_write)

Since I'm on a Mac, I installed them using homebrew. In a demo.d file I have the following:

import xlsxio_read;
import std.stdio;

pragma(lib, "libxlsxio_read.a");
pragma(lib, "libexpat.a");
pragma(lib, "libminizip.a");

string filename = "logistic_regression.xlsx";

void main (string[] args)
{
    if (args.length > 1)
        filename = args[1];

    xlsxioreader xlsxioread;

    writef("XLSX I/O library version %s\n", xlsxioread_get_version_string());
}

And in xlsxio_read.c (probably should call it something else), I simply import the library header:

#include <xlsxio_read.h>

When I try to compile it, I get a slew of errors about undefined symbols. It wasn't finding libexpat and libminizip so I copied those to my work directory and tried again. With that, most of the errors disappeared. The remaining ones are:

dmd demo.d xlsxio_read.c
ld: warning: ignoring file libminizip.a, building for macOS-x86_64 but attempting to link with file built for macOS-x86_64
Undefined symbols for architecture x86_64:
  "_unzClose", referenced from:
      _xlsxioread_close in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzCloseCurrentFile", referenced from:
      _expat_process_zip_file in libxlsxio_read.a(xlsxio_read.c.o)
      _xlsxioread_sheetlist_close in libxlsxio_read.a(xlsxio_read.c.o)
      _xlsxioread_sheet_close in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzGetCurrentFileInfo", referenced from:
      _iterate_files_by_contenttype_expat_callback_element_start in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzGetGlobalInfo", referenced from:
      _iterate_files_by_contenttype_expat_callback_element_start in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzGoToFirstFile", referenced from:
      _iterate_files_by_contenttype_expat_callback_element_start in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzGoToNextFile", referenced from:
      _iterate_files_by_contenttype_expat_callback_element_start in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzLocateFile", referenced from:
      _XML_Char_openzip in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzOpen", referenced from:
      _xlsxioread_open in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzOpen2", referenced from:
      _xlsxioread_open_filehandle in libxlsxio_read.a(xlsxio_read.c.o)
      _xlsxioread_open_memory in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzOpenCurrentFile", referenced from:
      _XML_Char_openzip in libxlsxio_read.a(xlsxio_read.c.o)
  "_unzReadCurrentFile", referenced from:
      _expat_process_zip_file in libxlsxio_read.a(xlsxio_read.c.o)
      _expat_process_zip_file_resume in libxlsxio_read.a(xlsxio_read.c.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Error: linker exited with status 1

From the first line of the error message, I gather I'm using the wrong minizip but I'm not sure how or why. What does "building for macOS-x86_64 but attempting to link with file built for macOS-x86_64" even mean?

Thanks,
confuzzled!!!

November 12, 2022

On Friday, 11 November 2022 at 03:15:17 UTC, confuzzled wrote:

>

When I try to compile it, I get a slew of errors about undefined symbols. It wasn't finding libexpat and libminizip so I copied those to my work directory and tried again. With that, most of the errors disappeared. The remaining ones are:

It seems that every time I resolve one of these undefined symbols issues, the compiler finds more. So I keep copying lib files from locations that are a path, to my working directory and linking them to my script. Is that the norm? Do I need to configure DMD somehow to recognize C libraries that are already in the path?

>

Thanks,
confuzzled!!!

November 12, 2022

On Saturday, 12 November 2022 at 02:45:52 UTC, confuzzled wrote:

>

It seems that every time I resolve one of these undefined symbols issues, the compiler finds more. So I keep copying lib files from locations that are a path, to my working directory and linking them to my script. Is that the norm? Do I need to configure DMD somehow to recognize C libraries that are already in the path?

The linker doesn't care if the libraries are C or D, and the compiler is only involved in that you can pass flags to the linker via the compiler command line.

These two things need to be true:

  • any link-time dependencies (object files, static libraries, shared libraries (link libraries on Windows)) need to be passed to the linker
  • the linker needs to know where to find libraries not on the default search path

The only thing the compiler passes along automatically are the object files generated from the source and the standard library it's building a binary. Anything else (including separately compiled object files), you have to pass along explicitly.

If you aren't explicitly passing any libraries along, then the linker won't know anything about them. The compiler doesn't know about them either, so can't pass them along for you.

If you are passing them along but they aren't on the default lib path, then the linker won't be able to find them.

Based on your description, it sounds like the last case is true for you. If so, if your libraries are in a common location, you can pass that path to the linker through dmd via -L<linker-specific-flag>. E.g., on Linux, -L-L/path/to/libs. On Windows, it depends on which linker you're using. For the Microsoft linker, it's -L/LIBPATH path\\to\\libs.

You can also just pass the full path to each library.

November 12, 2022

On Saturday, 12 November 2022 at 08:43:13 UTC, Mike Parker wrote:

>

On Saturday, 12 November 2022 at 02:45:52 UTC, confuzzled wrote:

The linker doesn't care if the libraries are C or D, and the compiler is only involved in that you can pass flags to the linker via the compiler command line.

Mike, first of all, thanks for the in depth response. That all makes sense. The issue I'm having is this: having made sure the two dependencies are available and building the libxlsxio_reader.a from the source without errors, why would I need to hunt down all the dependencies from that library to include them in my program?

I figured that importing the header and passing libxlsxio_read.a on the command line would be enough? Why would I have to search for libcrypto, libminizip, libexpat, and more that I haven't even figured out what library they are? I thought those dependencies would already be linked into libxlsxio_read.a which is a statically linked library.

I guess my noob is showing a lot. Again, thanks for your assistance.

confuzzled!!!

November 12, 2022

On Saturday, 12 November 2022 at 10:02:12 UTC, confuzzled wrote:

>

On Saturday, 12 November 2022 at 08:43:13 UTC, Mike Parker wrote:

>

On Saturday, 12 November 2022 at 02:45:52 UTC, confuzzled wrote:

The linker doesn't care if the libraries are C or D, and the compiler is only involved in that you can pass flags to the linker via the compiler command line.

Mike, first of all, thanks for the in depth response. That all makes sense. The issue I'm having is this: having made sure the two dependencies are available and building the libxlsxio_reader.a from the source without errors, why would I need to hunt down all the dependencies from that library to include them in my program?

I figured that importing the header and passing libxlsxio_read.a on the command line would be enough? Why would I have to search for libcrypto, libminizip, libexpat, and more that I haven't even figured out what library they are? I thought those dependencies would already be linked into libxlsxio_read.a which is a statically linked library.

Static library dependencies are resolved at link time. Anything they need to link with, your binary must link with. It's shared libraries that have their static dependencies all baked in.

November 12, 2022

On Saturday, 12 November 2022 at 11:44:06 UTC, Mike Parker wrote:

>

On Saturday, 12 November 2022 at 10:02:12 UTC, confuzzled wrote:

>

On Saturday, 12 November 2022 at 08:43:13 UTC, Mike Parker wrote:

>

On Saturday, 12 November 2022 at 02:45:52 UTC, confuzzled wrote:

The linker doesn't care if the libraries are C or D, and the compiler is only involved in that you can pass flags to the linker via the compiler command line.

Mike, first of all, thanks for the in depth response. That all makes sense. The issue I'm having is this: having made sure the two dependencies are available and building the libxlsxio_reader.a from the source without errors, why would I need to hunt down all the dependencies from that library to include them in my program?

I figured that importing the header and passing libxlsxio_read.a on the command line would be enough? Why would I have to search for libcrypto, libminizip, libexpat, and more that I haven't even figured out what library they are? I thought those dependencies would already be linked into libxlsxio_read.a which is a statically linked library.

Static library dependencies are resolved at link time. Anything they need to link with, your binary must link with. It's shared libraries that have their static dependencies all baked in.

Right, so I figured that the dependencies for for libxlsxio_read would be resolved when it was being compiled/linked. Therefore, when I used it later, I would just need to import its and include it on the command line. I didn't realize I would have to hunt down those libraries again and link them to my program, especially since I don't know what most of them are. I didn't have to provide them to the linker when I compiled libxlsxio_read.

Anyway, thanks for the explanation. I was definitely thinking and going about this all wrong. Appreciate the clarification.

confuzzled!!!

November 12, 2022

On Saturday, 12 November 2022 at 12:48:40 UTC, confuzzled wrote:

>

Right, so I figured that the dependencies for for libxlsxio_read would be resolved when it was being compiled/linked. Therefore, when I used it later, I would just need to import its and include it on the command line. I didn't

import its header and provide the library on the command line*

November 13, 2022

On Saturday, 12 November 2022 at 10:02:12 UTC, confuzzled wrote:

>

Why would I have to search for libcrypto, libminizip, libexpat, and more that I haven't even figured out what library they are? I thought those dependencies would already be linked into libxlsxio_read.a which is a statically linked library.

This is called transitive dependencies.

For Unix systems linking a static library is not a linking per se, it means putting object files (.o) into an archive (.a) using ar. So "libfoo.a" is just a set of object files that don't know anything about their dependencies and if you use something from libfoo.a, you might need to add another library to you link line. Technically there are two possible cases: (1) function that you use doesn't depend on anything else, then you don't need to add anything to your link line; and (2) function uses something from, say libbar.a - then you have to add libbar.a to your link line.

Dynamic libraries (.so) are treated the same way as executables: they are created by linker (ld for example) and so they have to have all symbols resolved. This means that if libfoo.so depends on libbar.a then the latter is already baked in into the former so your don't need to specify it when you link with libfoo.so. TBH I don't remember whether you should add libbar.so (dynamic library) which is a dependency of libfoo.so to your link line.