Commit 56bb66f2021c2c22a2582fb041671c8fa2bf0ca5

Authored by Jay Berkenbilt
Committed by GitHub
2 parents 6e580e24 d51bdcf6

Merge pull request #1448 from jberkenbilt/improve-windows-build

Enhance Windows build for local dev
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})