Commit 56bb66f2021c2c22a2582fb041671c8fa2bf0ca5
Committed by
GitHub
Merge pull request #1448 from jberkenbilt/improve-windows-build
Enhance Windows build for local dev
Showing
6 changed files
with
95 additions
and
135 deletions
CMakeLists.txt
| @@ -10,9 +10,8 @@ project(qpdf | @@ -10,9 +10,8 @@ project(qpdf | ||
| 10 | VERSION 12.1.1 | 10 | VERSION 12.1.1 |
| 11 | LANGUAGES C CXX) | 11 | LANGUAGES C CXX) |
| 12 | 12 | ||
| 13 | -# Enable correct rpath handling for MacOSX | ||
| 14 | -cmake_policy(SET CMP0042 NEW) | ||
| 15 | -# Honor CMAKE_REQUIRED_LIBRARIES when checking for include files | 13 | +# Honor CMAKE_REQUIRED_LIBRARIES when checking for include files. This |
| 14 | +# can be removed in cmake >= 3.17. | ||
| 16 | cmake_policy(SET CMP0075 NEW) | 15 | cmake_policy(SET CMP0075 NEW) |
| 17 | 16 | ||
| 18 | # *** OPTIONS *** | 17 | # *** OPTIONS *** |
| @@ -246,6 +245,7 @@ if(MSVC) | @@ -246,6 +245,7 @@ if(MSVC) | ||
| 246 | list(APPEND WINDOWS_WMAIN_LINK -link wsetargv.obj) | 245 | list(APPEND WINDOWS_WMAIN_LINK -link wsetargv.obj) |
| 247 | endif() | 246 | endif() |
| 248 | if(MINGW) | 247 | if(MINGW) |
| 248 | + get_filename_component(MINGW_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) | ||
| 249 | execute_process( | 249 | execute_process( |
| 250 | COMMAND gcc --print-file-name=CRT_glob.o | 250 | COMMAND gcc --print-file-name=CRT_glob.o |
| 251 | OUTPUT_VARIABLE CRT_GLOB_O | 251 | OUTPUT_VARIABLE CRT_GLOB_O |
| @@ -387,6 +387,11 @@ message(STATUS " QTC test coverage: ${ENABLE_QTC}") | @@ -387,6 +387,11 @@ message(STATUS " QTC test coverage: ${ENABLE_QTC}") | ||
| 387 | message(STATUS " include future changes: ${FUTURE}") | 387 | message(STATUS " include future changes: ${FUTURE}") |
| 388 | message(STATUS " system: ${CPACK_SYSTEM_NAME}") | 388 | message(STATUS " system: ${CPACK_SYSTEM_NAME}") |
| 389 | message(STATUS "") | 389 | message(STATUS "") |
| 390 | +if(MINGW) | ||
| 391 | + message(STATUS "MinGW compiler: ${CMAKE_CXX_COMPILER}") | ||
| 392 | + message(STATUS "MinGW bin dirrectory: ${MINGW_BIN_DIR}") | ||
| 393 | + message(STATUS "") | ||
| 394 | +endif() | ||
| 390 | message(STATUS "*** Options Summary ***") | 395 | message(STATUS "*** Options Summary ***") |
| 391 | foreach(PROP | 396 | foreach(PROP |
| 392 | COMPILE_OPTIONS INTERFACE_COMPILE_OPTIONS | 397 | COMPILE_OPTIONS INTERFACE_COMPILE_OPTIONS |
README-windows.md
| 1 | +Quick Start with JetBrains CLion | ||
| 2 | +================================ | ||
| 3 | + | ||
| 4 | +The following *should* work but has not been tested on a completely clean system with CLion. It may | ||
| 5 | +work with other "batteries-included" IDEs as well. | ||
| 6 | + | ||
| 7 | +* Install `external-libs` from [prebuilt static external libraries from the qpdf/external-libs | ||
| 8 | + github repository](https://github.com/qpdf/external-libs/releases) by unzipping the binary | ||
| 9 | + distribution into an otherwise clean source tree. | ||
| 10 | +* Using the default toolchain, you can create a cmake build of type *other than Debug*. A `Debug` | ||
| 11 | + build will not work with the external libraries since debug versions are not redistributable. If | ||
| 12 | + you want a Debug build, you'll have to build the external libraries yourself. The external-libs | ||
| 13 | + repo above can be a hint, or you can get them from other sources. | ||
| 14 | +* If you have MSVC, you can enable one of the `msvc` presets that you should see when you edit CMake | ||
| 15 | + configurations. | ||
| 16 | + | ||
| 17 | +In any of these, it should work to build and run the executables from the IDE. Note that, if you | ||
| 18 | +start a terminal from CLion and mingw is not in your path, the executables built my mingw won't run. | ||
| 19 | +If mingw is in your path, it should work. You can also start a mingw64 shell. The executables should | ||
| 20 | +work from there. This works because the cmake configuration copies the qpdf DLL into the bin | ||
| 21 | +directory. If you want the other executables to work, you should add the `libqpdf` directory of your | ||
| 22 | +build directory to your path or disable shared libraries. For more details, consult the qpdf manual | ||
| 23 | +and the rest of this file. | ||
| 24 | + | ||
| 25 | +Additional dependencies are required for running tests. For the foreseeable future, that requires | ||
| 26 | +msys2, though this may eventually not be the case. | ||
| 27 | + | ||
| 1 | Common Setup | 28 | Common Setup |
| 2 | ============ | 29 | ============ |
| 3 | 30 |
copy_dlls deleted
| 1 | -#!/usr/bin/env perl | ||
| 2 | -require 5.008; | ||
| 3 | -use warnings; | ||
| 4 | -use strict; | ||
| 5 | -use File::Basename; | ||
| 6 | -use File::Path qw(make_path); | ||
| 7 | - | ||
| 8 | -my $whoami = basename($0); | ||
| 9 | - | ||
| 10 | -usage() unless @ARGV == 3; | ||
| 11 | -my ($file, $libqpdf, $destdir) = @ARGV; | ||
| 12 | -my $filedir = dirname($file); | ||
| 13 | - | ||
| 14 | -my $sep = ($^O eq 'MSWin32' ? ';' : ':'); | ||
| 15 | -my @path = ($filedir, '.', split($sep, $ENV{'PATH'})); | ||
| 16 | -foreach my $var (qw(LIB)) | ||
| 17 | -{ | ||
| 18 | - if (exists $ENV{$var}) | ||
| 19 | - { | ||
| 20 | - push(@path, split($sep, $ENV{$var})); | ||
| 21 | - } | ||
| 22 | -} | ||
| 23 | - | ||
| 24 | -my $format = undef; | ||
| 25 | -my @to_find = get_dlls($file); | ||
| 26 | - | ||
| 27 | -my %final = (); | ||
| 28 | -my @notfound = (); | ||
| 29 | - | ||
| 30 | -while (@to_find) | ||
| 31 | -{ | ||
| 32 | - my $dll = shift(@to_find); | ||
| 33 | - my $found = 0; | ||
| 34 | - foreach my $dir ($libqpdf, @path) | ||
| 35 | - { | ||
| 36 | - if ((-f "$dir/$dll") && is_format("$dir/$dll", $format)) | ||
| 37 | - { | ||
| 38 | - if (! exists $final{$dll}) | ||
| 39 | - { | ||
| 40 | - if ($dir ne $libqpdf) | ||
| 41 | - { | ||
| 42 | - $final{$dll} = "$dir/$dll"; | ||
| 43 | - } | ||
| 44 | - push(@to_find, get_dlls("$dir/$dll")); | ||
| 45 | - } | ||
| 46 | - $found = 1; | ||
| 47 | - last; | ||
| 48 | - } | ||
| 49 | - } | ||
| 50 | - if (! $found) | ||
| 51 | - { | ||
| 52 | - push(@notfound, $dll); | ||
| 53 | - } | ||
| 54 | -} | ||
| 55 | -if (@notfound) | ||
| 56 | -{ | ||
| 57 | - die "$whoami: can't find the following dlls: " . | ||
| 58 | - join(', ', @notfound), "\n"; | ||
| 59 | -} | ||
| 60 | - | ||
| 61 | -make_path($destdir); | ||
| 62 | -foreach my $dll (sort keys (%final)) | ||
| 63 | -{ | ||
| 64 | - my $f = $final{$dll}; | ||
| 65 | - $f =~ s,\\,/,g; | ||
| 66 | - print "Copying $f to $destdir\n"; | ||
| 67 | - system("cp -p '$f' '$destdir'") == 0 or | ||
| 68 | - die "$whoami: copy $f to $destdir failed\n"; | ||
| 69 | -} | ||
| 70 | - | ||
| 71 | -sub get_dlls | ||
| 72 | -{ | ||
| 73 | - my @result = (); | ||
| 74 | - my $exe = shift; | ||
| 75 | - open(O, "objdump -p \"$exe\"|") or die "$whoami: can't run objdump\n"; | ||
| 76 | - while (<O>) | ||
| 77 | - { | ||
| 78 | - if (m/^\s+DLL Name:\s+(.+\.dll)/i) | ||
| 79 | - { | ||
| 80 | - my $dll = $1; | ||
| 81 | - $dll =~ tr/A-Z/a-z/; | ||
| 82 | - next if $dll =~ m/^(kernel32|user32|msvcrt|advapi32)\.dll$/; | ||
| 83 | - next if $dll =~ m/^(api-ms-win.*|ws2_32|crypt32|bcrypt)\.dll$/; | ||
| 84 | - push(@result, $dll); | ||
| 85 | - } | ||
| 86 | - elsif (m/^Magic.*\((PE.+?)\)/) | ||
| 87 | - { | ||
| 88 | - $format = $1; | ||
| 89 | - } | ||
| 90 | - } | ||
| 91 | - close(O); | ||
| 92 | - if (! defined $format) | ||
| 93 | - { | ||
| 94 | - die "$whoami: can't determine format of $exe\n"; | ||
| 95 | - } | ||
| 96 | - @result; | ||
| 97 | -} | ||
| 98 | - | ||
| 99 | -sub is_format | ||
| 100 | -{ | ||
| 101 | - my ($file, $format) = @_; | ||
| 102 | - $file =~ s,\\,/,g; | ||
| 103 | - # Special case: msvc*.dll seem to be able to behave both as 32-bit | ||
| 104 | - # and 64-bit DLLs. Either that, or this logic is wrong for those | ||
| 105 | - # DLLs and it doesn't matter because they're already installed on | ||
| 106 | - # my test system (which doesn't have msvc installed on it). | ||
| 107 | - if ($file =~ m,/msvc,i) | ||
| 108 | - { | ||
| 109 | - return 1; | ||
| 110 | - } | ||
| 111 | - my $result = 0; | ||
| 112 | - my $file_format = `file "$file"`; | ||
| 113 | - print "$file $format $file_format\n"; | ||
| 114 | - if ($? == 0) | ||
| 115 | - { | ||
| 116 | - if ($file_format =~ m/\Q${format}\E executable/) | ||
| 117 | - { | ||
| 118 | - $result = 1; | ||
| 119 | - } | ||
| 120 | - } | ||
| 121 | - $result; | ||
| 122 | -} | ||
| 123 | - | ||
| 124 | -sub usage | ||
| 125 | -{ | ||
| 126 | - die "Usage: $whoami {exe|dll} libqpdf-dir destdir\n"; | ||
| 127 | -} |
copy_dlls.ps1
0 → 100755
| 1 | +param ( | ||
| 2 | + [string]$exe, | ||
| 3 | + [string]$dest, | ||
| 4 | + [string]$mingwBinDir | ||
| 5 | +) | ||
| 6 | + | ||
| 7 | +function Get-DllDependencies { | ||
| 8 | + param([string]$binary) | ||
| 9 | + & objdump.exe -p $binary 2>$null | | ||
| 10 | + Select-String 'DLL Name:' | | ||
| 11 | + ForEach-Object { ($_ -split ':')[1].Trim() } | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +if (-not $exe -or -not $dest -or -not $mingwBinDir) { | ||
| 15 | + Write-Error "Usage: $(Split-Path -Leaf $MyInvocation.MyCommand.Name) -exe exe -dest dest -mingwBinDir mingw-bin-dir" | ||
| 16 | + exit 2 | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +New-Item -ItemType Directory -Path $dest -Force | Out-Null | ||
| 20 | +$dlls = [System.Collections.Generic.Queue[string]]::new() | ||
| 21 | +[void]$dlls.Enqueue($exe) | ||
| 22 | +$seen = @{} | ||
| 23 | +foreach ($dll in Get-DllDependencies $exe) { | ||
| 24 | + $dlls.Enqueue($dll) | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +while ($dlls.Count -gt 0) { | ||
| 28 | + $item = $dlls.Dequeue() | ||
| 29 | + $basename = if (Test-Path $item) { Split-Path $item -Leaf } else { $item } | ||
| 30 | + | ||
| 31 | + if ($seen[$basename]) { | ||
| 32 | + continue | ||
| 33 | + } | ||
| 34 | + $seen[$basename] = $true | ||
| 35 | + $full = Join-Path $mingwBinDir $basename | ||
| 36 | + if (Test-Path $full -PathType Leaf) { | ||
| 37 | + Copy-Item $full -Destination $dest -Force | ||
| 38 | + foreach ($dll in Get-DllDependencies $full) { | ||
| 39 | + $dlls.Enqueue($dll) | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | +} |
job.sums
| 1 | # Generated by generate_auto_job | 1 | # Generated by generate_auto_job |
| 2 | -CMakeLists.txt b9d848a8e701c06278371deba02cd67cc3db432bf4a36730a4d829d04f470e2d | 2 | +CMakeLists.txt e66fe7a418c9d241a577e1f811121235e288073a00744976accdc3f867fec620 |
| 3 | generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a86 | 3 | generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a86 |
| 4 | include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 | 4 | include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 |
| 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 | 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 |
qpdf/CMakeLists.txt
| @@ -72,13 +72,26 @@ if(MINGW) | @@ -72,13 +72,26 @@ if(MINGW) | ||
| 72 | set(ONE_GNU_DLL extra-dlls/libstdc++-6.dll) | 72 | set(ONE_GNU_DLL extra-dlls/libstdc++-6.dll) |
| 73 | add_custom_command(OUTPUT ${ONE_GNU_DLL} | 73 | add_custom_command(OUTPUT ${ONE_GNU_DLL} |
| 74 | COMMAND | 74 | COMMAND |
| 75 | - perl ${qpdf_SOURCE_DIR}/copy_dlls | ||
| 76 | - qpdf.exe | ||
| 77 | - ${CMAKE_BINARY_DIR}/libqpdf | ||
| 78 | - extra-dlls) | 75 | + pwsh.exe -NoProfile -ExecutionPolicy Bypass -Command |
| 76 | + "${qpdf_SOURCE_DIR}/copy_dlls.ps1" | ||
| 77 | + -exe $<TARGET_FILE:qpdf> | ||
| 78 | + -dest "${CMAKE_CURRENT_BINARY_DIR}/extra-dlls" | ||
| 79 | + -mingwBinDir "${MINGW_BIN_DIR}" | ||
| 80 | + VERBATIM | ||
| 81 | + COMMAND_EXPAND_LISTS | ||
| 82 | + DEPENDS qpdf) | ||
| 79 | add_custom_target(extra_dlls ALL DEPENDS ${ONE_GNU_DLL}) | 83 | add_custom_target(extra_dlls ALL DEPENDS ${ONE_GNU_DLL}) |
| 80 | add_dependencies(extra_dlls qpdf) | 84 | add_dependencies(extra_dlls qpdf) |
| 81 | if(BUILD_SHARED_LIBS) | 85 | if(BUILD_SHARED_LIBS) |
| 86 | + set(LIBQPDF_NAME get_filename_component($<TARGET_FILE:libqpdf> NAME)) | ||
| 87 | + add_custom_command( | ||
| 88 | + TARGET qpdf POST_BUILD | ||
| 89 | + COMMAND | ||
| 90 | + ${CMAKE_COMMAND} -E copy_if_different | ||
| 91 | + $<TARGET_FILE:libqpdf> | ||
| 92 | + $<TARGET_FILE_DIR:qpdf> | ||
| 93 | + VERBATIM | ||
| 94 | + COMMAND_EXPAND_LISTS) | ||
| 82 | set(EXTRA_DLL_COMPONENT ${COMPONENT_LIB}) | 95 | set(EXTRA_DLL_COMPONENT ${COMPONENT_LIB}) |
| 83 | else() | 96 | else() |
| 84 | set(EXTRA_DLL_COMPONENT ${COMPONENT_CLI}) | 97 | set(EXTRA_DLL_COMPONENT ${COMPONENT_CLI}) |