1

After successfully building Pdfium as per Google's docs, I created a new C++ console app with VS2022 and tried to embed .lib resulting from Pdfium build but, it results in several unresolved symbols which, I guess, should be included in standard C++. As an example, here is two of the unresolved symbols:

fx_string.obj: error LNK2001: unresolved external symbol "void __cdecl std::Cr::__libcpp_verbose_abort(char const *,...)"
fpdf_parser_utility.obj : error LNK2001: unresolved external symbol "public: class std::Cr::basic_ostream<char,struct std::Cr::char_traits<char> > & __cdecl std::Cr::basic_ostream<char,struct std::Cr::char_traits<char> >::write(char const *,__int64)"

Steps taken:

  • build Pdfium following docs steps using below args.gn:
    use_goma = false
    is_debug = false
    pdf_use_skia = false
    pdf_enable_xfa = false
    pdf_enable_v8 = false
    pdf_is_standalone = false
    is_component_build = false
    pdf_is_complete_lib = true
    
  • Created a simple C++ console app with following content (copied from Getting started):
    #include <iostream>
    #include "../PDFium/public/fpdfview.h"
    
    int main()
    {
         std::cout << "PDFium test!\n";
    
         FPDF_LIBRARY_CONFIG config{};
         config.version = 2;
         config.m_pUserFontPaths = NULL;
         config.m_pIsolate = NULL;
         config.m_v8EmbedderSlot = 0;
    
         FPDF_InitLibraryWithConfig(&config);
    
         FPDF_DestroyLibrary();
    
         return 0;
    }
    
  • Copied Pdfium's public folder and resulting .lib file into a separate folder of the project, added necessary fields for linker and set C++ language spec to stdc++20; below, the corresponding tags in .vcxproj
    <!-- other tags -->
    <ClCompile>
         <!-- other tags -->
         <LanguageStandard>stdcpp20</LanguageStandard>
         <LanguageStandard_C>stdc11</LanguageStandard_C>
    </ClCompile>
    <!-- other tags -->
    <Link>
         <SubSystem>Console</SubSystem>
         <GenerateDebugInformation>true</GenerateDebugInformation>
         <AdditionalLibraryDirectories>$(SolutionDir)PDFium\x64</AdditionalLibraryDirectories>
         <AdditionalDependencies>PDFium.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    

(Unsuccessful) Tests did

  • Tried to compile PDFium with and without pdf_is_complete_lib = true, and thus, linking also single .objs, and v8 and xfa support
  • Tried to compile with Microsoft's clang-cl instead of MSBuild (the one provided by Visual Studio's Native Development pack)
  • Tried to compile with depot tools's clang-cl (currently, version 16.0.0)
  • Tried several options found here and there on SO and on internet

Any help is appreciated. Thanks in advance.

Matteo Meil
  • 1,192
  • 10
  • 20
  • i don't know what your problem is but for what it is worth, I had so many problems building pdfium on Windows years ago that I just stopped trying to follow Google's instructions and put together my own Visual Studio solution. https://github.com/jwezorek/vs_pdfium it is kind of out of date now though. Ill probably pull new code and getting it up to date in 2023 at some point. – jwezorek Jan 03 '23 at 15:34
  • @jwezorek I took a look at your repo before writing this question, and also tried to take inspiration from what you did, but unsuccessfully. I will try again getting rid of `ninja` and letting VS do the magic – Matteo Meil Jan 03 '23 at 15:38

1 Answers1

2

After days of failures and (vain) research, I finally found the solution, posted here for future reference.

TL;DR;

Depending on flags set in args.gn, Pdfium will need at least the following to successfully build and start the Getting Started example:

  • if is_component_build = false and, thus pdf_is_complete_lib = true, .obj files built from libc++ and winmm.lib
  • if is_component_build = true and, thus pdf_is_complete_lib = false, all .dll resulting from compilation, i.e.:
    • absl.dll
    • icuuc.dll
    • libc++.dll
    • partition_alloc.dll
    • pdfium.dll
    • zlib.dll

Read also the important note below which tries to explain the difference between the two flags.

Long description

As per docs, once .ninja files has been generated as result of gn args <out_dir>, it can be seen which .obj, .lib and .dll files are needed to build pdfium_unitests.exe. Comparing those with the ones used to generate pdfium.lib (or pdfium.dll depending on flags, see below), it can be spotted the required libraries.

With is_component_build = false and pdf_is_complete_lib = true:

  • start default compilation with ninja -C <out_dir>; this also builds libc++;
  • generate pdfium.lib via ninja -C <out_dir> pdfium (will only execute a link step)
  • (optionally) generate a libc++.lib using depot tool's lld-link which will contain all .obj files from compilation of libc++:
    "C:\path\to\pdfium\third_party\llvm-build\Release+Asserts\bin\lld-link.exe" /lib /OUT:libc++.lib /nologo /WX /ignore:4221 <space-separated list of .obj files in C:\out_dir\obj\buildtools\third_party\libc++\libc++>
    
  • link pdfium.lib, all libc++'s .obj files in C:\out_dir\obj\buildtools\third_party\libc++\libc++ (or, libc++.lib from previous step), winmm.lib in your project; e.g.:
    <Link>
        <!-- other options -->
        <AdditionalDependencies>pdfium.lib;libc++.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
    

With is_component_build = true and pdf_is_complete_lib = false:

  • start compilation with ninja -C <out_dir> pdfium; will compile all the necessary .dlls along with .pdb and .lib files and put them in out_dir
  • link pdfium.lib in your project and copy emitted .dlls in output directory; assuming emitted files are in C:\pdfium\result, project's .vcxproj will look like this:
    <!-- ... -->
    <Link>
        <AdditionalLibraryDirectories>C:\pdfium\result</AdditionalLibraryDirectories>
        <AdditionalDependencies>pdfium.dll.lib</AdditionalDependencies>
    </Link>
    <!-- ... -->
    <PostBuildEvent>
        <Command>cmd /c "robocopy C:\pdfium\result $(OutDir) /xf *.lib &amp; if %errorlevel% geq 8 exit 0 else exit %errorlevel%"</Command>
    </PostBuildEvent>
    <!-- ... -->
    
    Note: the files you'll need are listed in tl;dr; section.
    Note 2: used robocopy because is more efficient than xcopy. Also, check on exit code is needed because of the value returned by robocopy

Important note

pdf_is_complete_lib and is_component_build will set, respectively, /MT and /MD flags during compilation.

Although might not seem a problem, MSBuild will complain if the two types are mixed and thus, you'll need either to recompile Pdfium or change the way your code is generated via Project Properties > C/C++ > Code Generation > Runtime Library.

For more information see Google docs, Microsoft docs on flags and linker warning and, eventually, this SO question which can help in choose the code generation that most suits your needs.

Matteo Meil
  • 1,192
  • 10
  • 20