diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ad224b..e26fa3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,8 @@ project(qpdf VERSION 12.1.1 LANGUAGES C CXX) -# Enable correct rpath handling for MacOSX -cmake_policy(SET CMP0042 NEW) -# Honor CMAKE_REQUIRED_LIBRARIES when checking for include files +# Honor CMAKE_REQUIRED_LIBRARIES when checking for include files. This +# can be removed in cmake >= 3.17. cmake_policy(SET CMP0075 NEW) # *** OPTIONS *** @@ -246,6 +245,7 @@ if(MSVC) list(APPEND WINDOWS_WMAIN_LINK -link wsetargv.obj) endif() if(MINGW) + get_filename_component(MINGW_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) execute_process( COMMAND gcc --print-file-name=CRT_glob.o OUTPUT_VARIABLE CRT_GLOB_O @@ -387,6 +387,11 @@ message(STATUS " QTC test coverage: ${ENABLE_QTC}") message(STATUS " include future changes: ${FUTURE}") message(STATUS " system: ${CPACK_SYSTEM_NAME}") message(STATUS "") +if(MINGW) + message(STATUS "MinGW compiler: ${CMAKE_CXX_COMPILER}") + message(STATUS "MinGW bin dirrectory: ${MINGW_BIN_DIR}") + message(STATUS "") +endif() message(STATUS "*** Options Summary ***") foreach(PROP COMPILE_OPTIONS INTERFACE_COMPILE_OPTIONS diff --git a/README-windows.md b/README-windows.md index 9940265..3395560 100644 --- a/README-windows.md +++ b/README-windows.md @@ -1,3 +1,30 @@ +Quick Start with JetBrains CLion +================================ + +The following *should* work but has not been tested on a completely clean system with CLion. It may +work with other "batteries-included" IDEs as well. + +* Install `external-libs` from [prebuilt static external libraries from the qpdf/external-libs + github repository](https://github.com/qpdf/external-libs/releases) by unzipping the binary + distribution into an otherwise clean source tree. +* Using the default toolchain, you can create a cmake build of type *other than Debug*. A `Debug` + build will not work with the external libraries since debug versions are not redistributable. If + you want a Debug build, you'll have to build the external libraries yourself. The external-libs + repo above can be a hint, or you can get them from other sources. +* If you have MSVC, you can enable one of the `msvc` presets that you should see when you edit CMake + configurations. + +In any of these, it should work to build and run the executables from the IDE. Note that, if you +start a terminal from CLion and mingw is not in your path, the executables built my mingw won't run. +If mingw is in your path, it should work. You can also start a mingw64 shell. The executables should +work from there. This works because the cmake configuration copies the qpdf DLL into the bin +directory. If you want the other executables to work, you should add the `libqpdf` directory of your +build directory to your path or disable shared libraries. For more details, consult the qpdf manual +and the rest of this file. + +Additional dependencies are required for running tests. For the foreseeable future, that requires +msys2, though this may eventually not be the case. + Common Setup ============ diff --git a/copy_dlls b/copy_dlls deleted file mode 100644 index 8c4d03f..0000000 --- a/copy_dlls +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env perl -require 5.008; -use warnings; -use strict; -use File::Basename; -use File::Path qw(make_path); - -my $whoami = basename($0); - -usage() unless @ARGV == 3; -my ($file, $libqpdf, $destdir) = @ARGV; -my $filedir = dirname($file); - -my $sep = ($^O eq 'MSWin32' ? ';' : ':'); -my @path = ($filedir, '.', split($sep, $ENV{'PATH'})); -foreach my $var (qw(LIB)) -{ - if (exists $ENV{$var}) - { - push(@path, split($sep, $ENV{$var})); - } -} - -my $format = undef; -my @to_find = get_dlls($file); - -my %final = (); -my @notfound = (); - -while (@to_find) -{ - my $dll = shift(@to_find); - my $found = 0; - foreach my $dir ($libqpdf, @path) - { - if ((-f "$dir/$dll") && is_format("$dir/$dll", $format)) - { - if (! exists $final{$dll}) - { - if ($dir ne $libqpdf) - { - $final{$dll} = "$dir/$dll"; - } - push(@to_find, get_dlls("$dir/$dll")); - } - $found = 1; - last; - } - } - if (! $found) - { - push(@notfound, $dll); - } -} -if (@notfound) -{ - die "$whoami: can't find the following dlls: " . - join(', ', @notfound), "\n"; -} - -make_path($destdir); -foreach my $dll (sort keys (%final)) -{ - my $f = $final{$dll}; - $f =~ s,\\,/,g; - print "Copying $f to $destdir\n"; - system("cp -p '$f' '$destdir'") == 0 or - die "$whoami: copy $f to $destdir failed\n"; -} - -sub get_dlls -{ - my @result = (); - my $exe = shift; - open(O, "objdump -p \"$exe\"|") or die "$whoami: can't run objdump\n"; - while () - { - if (m/^\s+DLL Name:\s+(.+\.dll)/i) - { - my $dll = $1; - $dll =~ tr/A-Z/a-z/; - next if $dll =~ m/^(kernel32|user32|msvcrt|advapi32)\.dll$/; - next if $dll =~ m/^(api-ms-win.*|ws2_32|crypt32|bcrypt)\.dll$/; - push(@result, $dll); - } - elsif (m/^Magic.*\((PE.+?)\)/) - { - $format = $1; - } - } - close(O); - if (! defined $format) - { - die "$whoami: can't determine format of $exe\n"; - } - @result; -} - -sub is_format -{ - my ($file, $format) = @_; - $file =~ s,\\,/,g; - # Special case: msvc*.dll seem to be able to behave both as 32-bit - # and 64-bit DLLs. Either that, or this logic is wrong for those - # DLLs and it doesn't matter because they're already installed on - # my test system (which doesn't have msvc installed on it). - if ($file =~ m,/msvc,i) - { - return 1; - } - my $result = 0; - my $file_format = `file "$file"`; - print "$file $format $file_format\n"; - if ($? == 0) - { - if ($file_format =~ m/\Q${format}\E executable/) - { - $result = 1; - } - } - $result; -} - -sub usage -{ - die "Usage: $whoami {exe|dll} libqpdf-dir destdir\n"; -} diff --git a/copy_dlls.ps1 b/copy_dlls.ps1 new file mode 100755 index 0000000..5982a28 --- /dev/null +++ b/copy_dlls.ps1 @@ -0,0 +1,42 @@ +param ( + [string]$exe, + [string]$dest, + [string]$mingwBinDir +) + +function Get-DllDependencies { + param([string]$binary) + & objdump.exe -p $binary 2>$null | + Select-String 'DLL Name:' | + ForEach-Object { ($_ -split ':')[1].Trim() } +} + +if (-not $exe -or -not $dest -or -not $mingwBinDir) { + Write-Error "Usage: $(Split-Path -Leaf $MyInvocation.MyCommand.Name) -exe exe -dest dest -mingwBinDir mingw-bin-dir" + exit 2 +} + +New-Item -ItemType Directory -Path $dest -Force | Out-Null +$dlls = [System.Collections.Generic.Queue[string]]::new() +[void]$dlls.Enqueue($exe) +$seen = @{} +foreach ($dll in Get-DllDependencies $exe) { + $dlls.Enqueue($dll) +} + +while ($dlls.Count -gt 0) { + $item = $dlls.Dequeue() + $basename = if (Test-Path $item) { Split-Path $item -Leaf } else { $item } + + if ($seen[$basename]) { + continue + } + $seen[$basename] = $true + $full = Join-Path $mingwBinDir $basename + if (Test-Path $full -PathType Leaf) { + Copy-Item $full -Destination $dest -Force + foreach ($dll in Get-DllDependencies $full) { + $dlls.Enqueue($dll) + } + } +} diff --git a/job.sums b/job.sums index fc4daa2..d30eb97 100644 --- a/job.sums +++ b/job.sums @@ -1,5 +1,5 @@ # Generated by generate_auto_job -CMakeLists.txt b9d848a8e701c06278371deba02cd67cc3db432bf4a36730a4d829d04f470e2d +CMakeLists.txt e66fe7a418c9d241a577e1f811121235e288073a00744976accdc3f867fec620 generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a86 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 diff --git a/qpdf/CMakeLists.txt b/qpdf/CMakeLists.txt index ee90a7b..ba6c469 100644 --- a/qpdf/CMakeLists.txt +++ b/qpdf/CMakeLists.txt @@ -72,13 +72,26 @@ if(MINGW) set(ONE_GNU_DLL extra-dlls/libstdc++-6.dll) add_custom_command(OUTPUT ${ONE_GNU_DLL} COMMAND - perl ${qpdf_SOURCE_DIR}/copy_dlls - qpdf.exe - ${CMAKE_BINARY_DIR}/libqpdf - extra-dlls) + pwsh.exe -NoProfile -ExecutionPolicy Bypass -Command + "${qpdf_SOURCE_DIR}/copy_dlls.ps1" + -exe $ + -dest "${CMAKE_CURRENT_BINARY_DIR}/extra-dlls" + -mingwBinDir "${MINGW_BIN_DIR}" + VERBATIM + COMMAND_EXPAND_LISTS + DEPENDS qpdf) add_custom_target(extra_dlls ALL DEPENDS ${ONE_GNU_DLL}) add_dependencies(extra_dlls qpdf) if(BUILD_SHARED_LIBS) + set(LIBQPDF_NAME get_filename_component($ NAME)) + add_custom_command( + TARGET qpdf POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E copy_if_different + $ + $ + VERBATIM + COMMAND_EXPAND_LISTS) set(EXTRA_DLL_COMPONENT ${COMPONENT_LIB}) else() set(EXTRA_DLL_COMPONENT ${COMPONENT_CLI})