curl / Mailing Lists / curl-library / Single Mail
Buy commercial curl support. We help you work out your issues, debug your libcurl applications, use the API, port to new platforms, add new features and more. With a team lead by the curl founder Daniel himself.

Suggestions to improve MSVC support

From: maiddaisuki via curl-library <curl-library_at_lists.haxx.se>
Date: Wed, 29 Apr 2026 04:34:29 +0000

Hello,

Before I start, I want to mention that I wrote original draft for this message back in January. I was unable to send it to the list - I simply could not subscribe because outlook was rejecting all messages from mailing lists which use mailman. The original draft was referencing 8.17 release, and it so happened that just around that time 8.18 was released, which seemed to have the same issues. I have encountered the same issue with 8.19 release.

The rest of the message is rewrite of my original unsent draft. Some references may be really outdated.

Before I start, I need to add some context:

First, I was helping to test upcoming gettext-1.0 release with MSVC toolchain. This release has new tool which has dependency on libcurl, so I had to figure out how to build libcurl and its dependencies with MSVC.

NOTE: when I say "MSVC", I also mean clang-cl.exe.

I was building with minimal set of dependencies: libpsl and libidn2 (which is also a dependency of libpsl). Both of them share the same dependencies: libiconv, libunistring and optionally libintl.

Second, I'm using my own build script for building packages with MSVC. It is rather simple script which runs `configure` -> `make` -> `make check` -> `make install DESTDIR...` or equivalent meson/cmake steps for each package. The script is on GitHub[1], so you can try using it to build curl with MSVC if you're interested. It can make your life easier if you will try to implement suggestions for autotools described below.

I was trying to use both cmake and autotools with various configurations, e.g. static vs shared CRT. Building with cmake worked just fine in "usual configuration", but I've run into some issues. Autotools almost works; there are a few little improvements that can be made to make it work with MSVC. Unfortunately, MSVC builds with autotools may fail because of one annoying libtool issue that I have reported[2] to bug-libtool.

Section 1: Issues with CMake

First, I want to mention the name of import library used with MSVC - libcurl_imp.lib; please consider using curl.lib instead. Since curl installs libcurl.pc, this change would make it usable with pkgconf; it has a feature which allows to convert -L and -l flags in .pc files to MSVC-style, e.g. it converts -lcurl to curl.lib. Build systems like meson make use of it, however current name libcurl_imp.lib will not allow to make use of this feature (results in link error because there is no curl.lib, or worse it is a static library).

Second, I would suggest to get rid of option `CURL_STATIC_CRT`, and instead use `CMAKE_MSVC_RUNTIME_LIBRARY`[3]. It allows to do the same things, but unlike `CURL_STATIC_CRT` it is an actual CMake option and it has advantage that it allows to link against debug versions of CRT (/MDd and /MTd options).

When linking against static CRT, all dependencies must be static as well (compiled with /MT or /MTd), however my attempts to build with static CRT and static dependencies failed:

```
libcurl.lib(version.c.obj) : error LNK2019: unresolved external symbol __imp_psl_check_version_number referenced in function curl_version
libcurl.lib(version.c.obj) : error LNK2019: unresolved external symbol __imp_idn2_check_version referenced in function curl_version
libcurl.lib(idn.c.obj) : error LNK2001: unresolved external symbol __imp_idn2_check_version
libcurl.lib(cookie.c.obj) : error LNK2019: unresolved external symbol __imp_psl_is_cookie_domain_acceptable referenced in function Curl_cookie_add
libcurl.lib(idn.c.obj) : error LNK2019: unresolved external symbol __imp_idn2_lookup_u8 referenced in function Curl_idn_decode
libcurl.lib(idn.c.obj) : error LNK2019: unresolved external symbol __imp_idn2_to_unicode_8z8z referenced in function Curl_idn_encode
libcurl.lib(idn.c.obj) : error LNK2019: unresolved external symbol __imp_idn2_free referenced in function Curl_idn_decode
libcurl.lib(psl.c.obj) : error LNK2019: unresolved external symbol __imp_psl_free referenced in function Curl_psl_destroy
libcurl.lib(psl.c.obj) : error LNK2019: unresolved external symbol __imp_psl_builtin referenced in function Curl_psl_use
libcurl.lib(psl.c.obj) : error LNK2019: unresolved external symbol __imp_psl_latest referenced in function Curl_psl_use
src\curl.exe : fatal error LNK1120: 9 unresolved externals
```

Both compiler and linker flags were obtained with pkgconf.exe, but seemingly --static flag was not used. This also means that libraries from Libs.private were not added to link command, which would result in more undefined references later.

(I used my build script to patch installed libidn2.pc and libpsl.pc to add Cflags.private, so they would work properly with `pkgconf --static`.)

I think that checks for dependencies should also perform link tests. In case if pkgconf/pkg-config was able to find the library, but the link test failed, it should try using this dependency as static. With static CRT only static dependencies should be used. This is also an issue when using pkg-config/pkgcong with configure script. Also, when only static libcurl is built, you want to make sure that `-DCURL_STATICLIB` is used when building curl.exe.

Section 2: Using Autotools

I'm not sure if they are of any use, but I have attached compressed configure.log, build.log and test.log which respectively contain output from configure, make (successful build with one fix applied) and `make check`. (`make check` fails pretty badly, though)

My first configure invocation failed here:

```
***
*** Warning: This configure script does not have information about the
*** compiler you are using, relative to the flags required to enable or
*** disable generation of debug info, optimization options or warnings.
***
*** Whatever settings are present in CFLAGS will be used for this run.
***
*** If you wish to help the curl project to better support your compiler
*** you can report this and the required info on the libcurl development
*** mailing list: https://lists.haxx.selistinfo/curl-library/
***
checking for code coverage support... no
checking whether build target is a native Windows one... yes
checking if compiler halts on compilation errors... yes
checking if compiler halts on negative sized arrays... yes
checking if compiler halts on function prototype mismatch... no
configure: error: compiler does not halt on function prototype mismatch.
```

First, configure does not recognize cl.exe. You can do simple compilation check for _MSC_VER; it should cover cl.exe as well as clang-cl.exe. Additionally, to check whether you're compiling for static or shared CRT, check for _DLL macro; it is only defined with /MD and /MDd. Note that while mingw-w64 supports only shared CRT, it still defines _DLL for compatibility.

Second, you may see configure complaining about cl.exe not halting on mismatched function prototypes; it simply produces warning C4028[4]. It can be turned into an error with -we4048. Adding -we4048 to CFLAGS allows configure script to succeed.

Here's one thing I've noticed:

```
checking for x86_64-w64-mingw32-pkg-config... /j/x86_64-msvc-windows/md/bin/x86_64-w64-mingw32-pkg-config
```

It appears to me that configure uses `AC_CHECK_TOOL` to find pkg-config, which is problematic. I build pkgconf earlier with my script and set `PKG_CONFIG` to its absolute filename, but it is ignored when you use `AC_CHECK_TOOL`. Here it found correct "pkg-config.exe" only because I started installing it as an alias for pkgconf.exe after I noticed it here; otherwise it could find "pkg-config.exe" which is a Cygwin tool and it would fail horribly. It probably would be more appropriate to use PKG_* macros from pkg.m4.

Running `make` to build. Here, when I tried to build curl 8.17 (but not 8.18 and 8.19), I ran into libtool issue[2] I mentioned earlier:

```
libtool: warning: Linker path does not have real file for library -lwldap32.
libtool: warning: I have the capability to make that library automatically link in when
libtool: warning: you link to this library. But I can only do this if you have a
libtool: warning: shared version of the library, which you do not appear to have
libtool: warning: because I did check the linker path looking for a file starting
libtool: warning: with wldap32 and none of the candidates passed a file format test
libtool: warning: using a file magic. Last file checked: /cygdrive/c/WINDOWS/system32/secur32.dll
libtool: warning: Linker path does not have real file for library -liphlpapi.
libtool: warning: I have the capability to make that library automatically link in when
libtool: warning: you link to this library. But I can only do this if you have a
libtool: warning: shared version of the library, which you do not appear to have
libtool: warning: because I did check the linker path looking for a file starting
libtool: warning: with iphlpapi and none of the candidates passed a file format test
libtool: warning: using a file magic. Last file checked: /cygdrive/c/PROGRA~2/WI3CF2~1/10/lib/100261~1.0/um/x64/iphlpapi.lib
```

With curl 8.18, curl-4.dll was created successfully. However, building curl.exe failed:

```
make[1]: *** No rule to make target 'curl.obj', needed by 'curl.exe'. Stop.
make[1]: *** Waiting for unfinished jobs....
```

This issue comes from src/Makefile.am:

```
if HAVE_WINDRES
.rc.o:
      $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $_at_
endif
```

It hardcodes .o extension instead of using $(OBJEXT) (which is obj for MSVC). With MSVC, I would suggest not to use windres.exe and instead use windres-rc[5] wrapper for rc.exe. Found windres.exe may be a cygwin/msys tool. You can see how windres-rc is used in winpthreads' configure.ac[6] as a reference.

After modifying src/Makefile.am to use $(OBJEXT), building curl.exe succeeds. I noticed this warning:

```
cl : Command line warning D9002 : ignoring unknown option '-municode'
```

This option is only needed with mingw-w64 toolchains, so you would want to arrange not to pass it to MSVC-like compilers.

I hope I provided enough information with this message. Please let me know if there is anything else you could find helpful.

- Kirill Makurin

[1] https://github.com/maiddaisuki/gnu-libs-with-msvc
[2] https://lists.gnu.org/archive/html/bug-libtool/2026-01/msg00014.html
[3] https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html
[4] https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4028
[5] https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/buildsystems/make_wrapper/windres-rc
[6] https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/configure.ac


-- 
Unsubscribe: https://lists.haxx.se/mailman/listinfo/curl-library
Etiquette:   https://curl.se/mail/etiquette.html
Received on 2026-04-29