Linker errors when installing on Windows 10 (as .dll) using MSVC

Platform and tools

  • Operating System: Windows 10 Home (64bit)
  • Project setup: Microsoft Visual Studio 2019 community edition
  • Compiler: Microsoft (R) C/C++ Optimizing Compiler Version 19.25.28614
  • Compilation option: Microsoft Visual C++ (not msys2)
  • Build architecture: x64

Issues

Note: Following the steps available here results in an error-free build of igraph as a Static Library, and igraphtest works. The issues mentioned below concern only building and using igraph as a Dynamic Library (.dll).

Note: I generally only develop for Linux and MacOS, and so there is a good chance I missed something crucial. If that is the case, you have my sincerest apologies for taking your time.

1. Linker errors when building igraph as a .dll

The Visual Studio project was setup as recommended. Then in project properties, the Configuration Type was changed to “Dynamic Library (.dll)”.

Building the project resulted in the following linker errors:

a) Error LNK2019 unresolved external symbol _plfit_fmin referenced in function plfit_rbinom igraph-0.8.1-msvc\rbinom.obj

b) Error LNK2019 unresolved external symbol _plfit_round referenced in function plfit_rzeta igraph-0.8.1-msvc\sampling.obj

c) Error LNK2005 expm1 already defined in random.obj igraph-0.8.1-msvc\ucrt.lib(api-ms-win-crt-math-l1-1-0.dll)

Workarounds

Errors (a) and (b) were resolved by commenting out declarations of functions fmin() and round() in src/plfit/platform.h. These definitions are enclosed in #ifdef _MSC_VER, which is expected to be true when using MSVC. In this case however, it is MSVC where including these results in this issue. Perhaps this check requires review?

Error (c ) was resolved by explicitly adding HAVE_EXPM1 as a preprocessor definition. The code defining the expm1() function is enclosed in #ifndef HAVE_EXPM1. Therefore, defining HAVE_EXPM1 disables the definition.

Resolution of all three issues results in a successful build. The igraphtest project, after re-configuring it to use the dll, also runs successfully.

2. Error while linking igraph to a custom C++ application

In my own application, I use igraph_i_set_attribute_table(&igraph_cattribute_table). Building my application results in the following linker error:

Error LNK2001 unresolved external symbol igraph_cattribute_table

Please note that by adding igraph_i_set_attribute_table(&igraph_cattribute_table) to the igraphtest project results in the same error.

Workaround

In the igraph source, include/igraph_attribute.h declares igraph_cattribute_table as follows:

extern const igraph_attribute_table_t igraph_cattribute_table;

Replacing extern with DECLDIR and rebuilding igraph resolves the linker error, as DECLDIR enables the declaration to be included in the public interface of igraph.dll.

My questions

  1. Would it be feasible for you to recommend how the entire igraph test suite can be run on Windows with Visual Studio 2019? As the igraphtest project lacks coverage, perhaps running the entire test suite would be helpful in highlighting issues such as those mentioned above?

  2. Do the above mentioned issues need to be resolved by updating the igraph code base, or did I simply configure the project incorrectly?

It would be great to have igraph work on Windows 10 just as it does on MacOS and Linux. I’d very much appreciate your thoughts and feedback on this issue.

Thanks & Regards,
Fahad

Thank you for reporting these. It looks like these are real issues in igraph that should be addressed. Unfortunately, none of us use Windows as their main system, which makes it a bit difficult to do so.

I’m a bit surprised to see that the DECLDIR issue comes up with Visual Studio, but not with MinGW. I believe MinGW supports __declspec(dllexport)/__declspec(dllimport), yet I get no test failure with it. Does anyone have any insight?

Yes, most likely it needs review, but this could actually be an issue that is attributed to MSVC versions. I definitely remember that old versions of MSVC did not provide fmin() and round().(round() is C99 as far as I know and older versions of MSVC are notoriously bad at supporting C99 stuff).

On Linux and macOS, this problem is largely solved because the configure script checks the system for features (i.e. the presence or absence of certain functions), and then provides alternative implementations only if the function is missing. On MSVC we don’t have that luxury so we provide a pre-generated config.h that we think is probably valid on Windows systems, but we cannot be sure. Does anyone know whether we could determine the presence or absence of fmin() and round() with MSVC by relying on macros only? (I’m thinking about some kind of version number check in the code).

The problem with expm1() can probably also be explained by this; expm1() is also C99, so older MSVC versions that do not support expm1() need an alternative implementation, that’s why HAVE_EXPM1 is not defined by default.

Alternatively, we could simply drop support for non-C99 compilers, assuming that we do not run into troubles then with compiling the Python interface for Python 2.x.

@fahad Can you please try replacing #ifdef _MSC_VER in src/plfit/platform.h with #if defined(_MSC_VER) && _MSC_VER < 1800? I think this should do the trick in your case, at least with errors (a) and (b).

As for error (c ), I think it could be resolved in config.h with:

#if defined(_MSC_VER) && _MSC_VER >= 1800
#  define HAVE_EXPM1 1
#endif

I don’t have a Windows machine around to test things with; any help would be appreciated here.

This also has to be solved for the conda package. Thanks for the suggested patches @tamas, I’ve applied them in the build feedstock for python-igraph, it’s running now, fingers crossed.

@szhorvat, @vtraag, @tamas: Many thanks to all of you for your prompt responses.

In an attempt to resolve an non-igraph related issue, I recompiled igraph with the runtime library set to Multi-threaded (/MT) instead of the default Multi-threaded DLL (/MD). This resulted in another linker error; this time about rint() being already defined. This is easily ressolved by setting HAVE_RINT.

If I may, I’d like to suggest the following:

  1. Before making any changes to the code, the build process should be tested with all available configurations, as different applications may require different build configurations. I’ll investigate this a bit further on my end. If I find any further issues, I’ll report those here. It might be safer to proceed with a solution once all the issues have been reported.

  2. Test cases should be ported to Windows. It does not seem possible to run the test suite on Windows at this time. This makes it a little scary to use the library, as something could fail at any point, or generate incorrect results. Are there any plans for porting the complete test suite to Windows?

@tamas Done. It seems to work just fine; both the static and dynamic library builds succeed.

Thanks for the feeback!

That would be great, thanks. Note that the biggest issue here is that none of the developers use Windows for development; personally, I don’t even have access to Windows machines, so the best that we can do is to test igraph in CI environments. This is a bit tedious, especially considering that there are currently hundreds of warnings produced by MSVC when it compiles igraph, and for most of them we have no idea how to fix them apart from trial-and-error (and it’s even only a single version of MSVC so we can never be sure that we don’t break something for some other version of MSVC). The best that we can promise right now is that we keep on testing igraph in CI environments and try to fix compilation failures as they appear. In the long run, we would need someone who uses igraph primarily in a Windows environment on a daily basis so he/she can report any issues back to us that are not caught by the CI env runs. So, please keep us posted if you find any further issues!

As for the test suite: igraph on Windows is sort-of tested indirectly via the Python interface; the Python interface is compiled in MSVC (so we can provide Windows wheels in PyPI) and then the whole test suite of the Python interface is executed there so that should cover significant parts of the library. The current autotest-based test suite would be very hard to port to Windows.

There are mid-term plans to switch igraph’s build system from autotools to CMake and CTest; in theory, this would allow us to run the test suite directly on Windows as CMake would generate a Visual Studio project for the tests. However, I don’t know how that would work out in practice due to lack of experience with CMake in a Windows environment.

1 Like

I completely understand. I’ll do my best to contribute my experience.

There are some interesting features in Visual Studio 2019, including the possibility to directly import a CMake-based project. I imported a couple of my Linux-based CMake projects quite easily. With just a few configuration changes here and there, everything worked quite well, including automated tests with Catch2.

Once you have ported the build to CMake, please do let me know. I might be able to help with testing on Windows.

FYI, I have started working on CMake support; you can follow my progress in this branch. RIght now it is tested only on macOS and as a static library - so not all parts of the library are actually compiled yet, but the parts that are compiled seem to work nicely (you can even run some of the unit tests with CTest).

1 Like