X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=nsiswrapper%2Fnsiswrapper.pl;h=af466a81d6ca9f638e13390a85be7a295d8c9add;hb=433074544daf2c2c40f465f1150fe0b354afc69a;hp=344e5c00a9ee7d22a2641cd4e06435e87f4acf57;hpb=1f26dc230ae3636fe09265c19f2017c636322d40;p=fedora-mingw.git diff --git a/nsiswrapper/nsiswrapper.pl b/nsiswrapper/nsiswrapper.pl index 344e5c0..af466a8 100755 --- a/nsiswrapper/nsiswrapper.pl +++ b/nsiswrapper/nsiswrapper.pl @@ -22,6 +22,8 @@ use strict; use Getopt::Long; use Pod::Usage; +use File::Temp qw/tempfile/; +#use Data::Dumper; =pod @@ -88,6 +90,51 @@ License files. It's a good idea to examine the NSIS command script, to check that nsiswrapper is including all the right dependencies. +=head1 ROOTS (FILES AND DIRECTORIES) + +Each parameter should refer to a file or directory which is to be +included in the installer. + +These are known as "roots" because we also automatically add any +dependencies to the list of files. Thus if a Windows executable +requires any DLLs, those are added automatically. DLLs are searched +for on the current C<$PATH> (environment variable). + +We choose the install location by removing any common prefix from the +names of roots, which generally ensures that the original directory +structure is preserved. Thus for example if the original roots (and +any dependencies) are: + + /usr/i686-pc-mingw32/sys-root/mingw/bin/program.exe + /usr/i686-pc-mingw32/sys-root/mingw/bin/library.dll + /usr/i686-pc-mingw32/sys-root/mingw/etc/config + +then the install directory will look like this: + + $INSTDIR/bin/program.exe + $INSTDIR/bin/library.dll + $INSTDIR/etc/config + +(C<$INSTDIR> is the installation directory chosen by the user at +install time). + +You can also specify the install location (relative to C<$INSTDIR>) by +adding roots of the form: + + source=destination + +for example: + + /usr/i686-pc-mingw32/sys-root/mingw/bin/program.exe=program.exe + /usr/i686-pc-mingw32/sys-root/mingw/bin/library.dll=library.dll + /usr/i686-pc-mingw32/sys-root/mingw/etc/config=conf/config + +which results in: + + $INSTDIR/program.exe + $INSTDIR/library.dll + $INSTDIR/conf/config + =head1 OPTIONS =over 4 @@ -111,6 +158,12 @@ Normally this program just prints out the NSIS installer command script. However if you supply this option, then we run C and attempt to generate an actual Windows installer. +=item B<--with-gtk> + +GTK programs should normally supply this option. It ensures that the +correct files are copied and/or created by the installer for GTK +programs to work. + =item B<--name "Name"> Set the long name of the installer. @@ -162,21 +215,32 @@ This is the same as the C option to NSIS. =cut my $objdump; +my %files; + my $help = ''; my $man = ''; my $verbose = ''; -my %files; +my $run = ''; +my $with_gtk = ''; my $name = ''; my $outfile = 'installer.exe'; my $installdir = ''; my $installdirregkey = ''; +# XXX Should make these configurable. +my $mingw32_prefix = '/usr/i686-pc-mingw32/sys-root/mingw'; +my $mingw32_bindir = $mingw32_prefix . '/bin'; +my $mingw32_libdir = $mingw32_prefix . '/lib'; +my $mingw32_sysconfdir = $mingw32_prefix . '/etc'; + sub get_options { my $result = GetOptions ( "help|?" => \$help, "man" => \$man, "verbose" => \$verbose, + "run" => \$run, + "with-gtk" => \$with_gtk, "name=s" => \$name, "outfile=s" => \$outfile, "installdir=s" => \$installdir, @@ -191,15 +255,48 @@ sub get_options # Add the roots to the list of files. die "nsiswrapper: no roots specified: use --help for more help\n" if @ARGV == 0; - foreach (@ARGV) { - my $exec = 0; - $exec = 1 if m/\.exe$/i; + foreach my $file (@ARGV) { + my ($dir, $exec) = (0, 0); + + # Is it source=destination? + my ($source, $dest); + if ($file =~ /^(.*)=(.*)$/) { + $source = $1; + $dest = $2; + } else { + $source = $file; + } + + die "$source: not a file or directory\n" + unless -f $source || -d $source; - $files{$_} = { - name => $_, + $exec = 1 if $source =~ m/\.exe$/i; + $dir = 1 if -d $source; + + $files{$source} = { + name => $source, root => 1, - dir => -d $_, + dir => $dir, exec => $exec, + }; + + # Deal with explicit destination. + if (defined $dest) { + my ($install_dir, $install_name); + + if ($dest =~ m{(.*)/(.*)}) { + $install_dir = $1; + $install_name = $2; + } else { + $install_dir = "."; + $install_name = $dest; + } + + # Convert / in install_dir into backslashes. + $install_dir =~ s{/}{\\}g; + + $files{$source}->{install_dir} = $install_dir; + $files{$source}->{install_name} = $install_name; } } @@ -208,6 +305,7 @@ sub get_options # Massage the first root into a suitable package name. $_ = $ARGV[0]; s{.*/}{}; + s{=.*$}{}; s{\.\w\w\w\w?$}{}; $_ = ucfirst; $name = $_; @@ -281,29 +379,49 @@ sub print_config # Starting at the roots, get the dependencies. +my $missing_deps = 0; + sub do_dependencies { - my $gotem = 1; + my $deps_added = 1; + + while ($deps_added > 0) { + $deps_added = 0; - while ($gotem) { - $gotem = 0; foreach (keys %files) { my @deps = get_deps_for_file ($_); # Add the deps as separate files. foreach (@deps) { - unless (exists $files{$_}) { - $files{$_} = { - name => $_, - root => 0, - dir => 0, - exec => 0, - }; - $gotem = 1; - } + $deps_added += add_file_unless_exists ( + $_, + root => 0, + dir => 0, + exec => 0 + ); } } } + + die "please correct missing dependencies shown above\n" + if $missing_deps > 0; +} + +sub add_file_unless_exists +{ + my $name = shift; + my %details = @_; + + unless (exists $files{$name}) { + die "$name: not a file or directory\n" unless -f $name || -d $name; + + $details{name} = $name; + $files{$name} = \%details; + + return 1; + } else { + return 0; + } } my $path_warning = 0; @@ -340,6 +458,7 @@ sub get_deps_for_file push @deps, $found; } else { warn "MISSING DEPENDENCY: $_ (for $file)\n"; + $missing_deps++; unless ($path_warning) { warn "You may need to add the directory containing this file to your \$PATH\n"; $path_warning = 1; @@ -377,6 +496,66 @@ sub is_windows_system_dll $_ eq 'user32.dll' } +# Add Gtk dependencies, if --with-gtk. + +sub do_gtk +{ + add_file_unless_exists ( + "$mingw32_libdir/gtk-2.0", + root => 0, + dir => 1, + exec => 0, + install_dir => "lib", + install_name => "gtk-2.0" + ); + + add_file_unless_exists ( + "$mingw32_libdir/pango", + root => 0, + dir => 1, + exec => 0, + install_dir => "lib", + install_name => "pango" + ); + + add_file_unless_exists ( + "$mingw32_sysconfdir/fonts", + root => 0, + dir => 1, + exec => 0, + install_dir => "etc", + install_name => "fonts" + ); + + add_file_unless_exists ( + "$mingw32_sysconfdir/gtk-2.0", + root => 0, + dir => 1, + exec => 0, + install_dir => "etc", + install_name => "gtk-2.0" + ); + + add_file_unless_exists ( + "$mingw32_sysconfdir/pango", + root => 0, + dir => 1, + only_mkdir => 1, + exec => 0, + install_dir => "etc", + install_name => "pango" + ); + + # We need to run pango-querymodules after installation to + # rebuild etc\pango\pango.modules. + add_file_unless_exists ( + "$mingw32_bindir/pango-querymodules.exe", + root => 0, + dir => 0, + exec => 0 + ); +} + # Decide how we will name the output files. This removes the # common prefix from filenames, if it can determine one. @@ -384,13 +563,18 @@ sub install_names { my @names = keys %files; + # Don't care about files that already have an install + # directory/name defined, ie. they were specified as source=dest + # on the command line. + @names = grep { ! exists $files{$_}->{install_name} } @names; + # Determine if all the names share a common prefix. my @namelens = map { length } @names; my $shortest = min (@namelens); my $prefixlen; for ($prefixlen = $shortest; $prefixlen >= 0; --$prefixlen) { - my @ns = map { $_ = substr $_, 0, $prefixlen } @names; + my @ns = map { substr $_, 0, $prefixlen } @names; last if same (@ns); } @@ -398,7 +582,7 @@ sub install_names # Remove the prefix from each name and save the install directory # and install filename separately. - foreach my $name (keys %files) { + foreach my $name (@names) { my $install_as = substr $name, $prefixlen; my ($install_dir, $install_name); @@ -526,12 +710,33 @@ EOT # If it's a directory, we copy it recursively, otherwise # just copy the single file. if ($files{$_}->{dir}) { - print $io " File /r \"$_\"\n"; + if ($files{$_}->{only_mkdir}) { + # This is a hack to allow us to create empty directories. + my $install_dir = $files{$_}->{install_dir}; + my $install_name = $files{$_}->{install_name}; + print $io " CreateDirectory \"\$INSTDIR\\$install_dir\\$install_name\"\n"; + } else { + print $io " File /r \"$_\"\n"; + } } else { print $io " File \"$_\"\n"; } } + # GTK? + if ($with_gtk) { + my $install_dir = $files{"$mingw32_bindir/pango-querymodules.exe"}->{install_dir}; + my $install_name = $files{"$mingw32_bindir/pango-querymodules.exe"}->{install_name}; + + # This particular piece of Windows stupidity is documented here: + # http://forums.winamp.com/showthread.php?postid=438771#post438771 + # http://forums.winamp.com/printthread.php?s=53c76b4ae4221ff1d9dc361fc5bf7ea2&threadid=231797 + print $io "\n"; + print $io " ReadEnvStr \$0 COMSPEC\n"; + print $io " SetOutPath \"\$INSTDIR\"\n"; + print $io " nsExec::ExecToLog '\$0 /C $install_dir\\$install_name > etc\\pango\\pango.modules'\n" + } + print $io <{install_dir}; my $install_name = $files{$_}->{install_name}; if ($files{$_}->{dir}) { - print $io " RMDir /r \"\$INSTDIR\\$install_dir\"\n\n"; + print $io " RMDir /r \"\$INSTDIR\\$install_dir\\$install_name\"\n\n"; $olddir = ''; # Don't double-delete directory. } else { print $io " Delete /rebootok \"\$INSTDIR\\$install_dir\\$install_name\"\n"; @@ -612,7 +818,15 @@ Section -post WriteUninstaller "\$INSTDIR\\Uninstall $name.exe" SectionEnd EOT +} + +# Run makensis on the named file. +sub run_makensis +{ + my $filename = shift; + + system ("makensis", $filename) == 0 or die "makensis: $?" } # Main program. @@ -622,10 +836,18 @@ sub main get_options (); check_prereqs (); print_config () if $verbose; + do_gtk () if $with_gtk; do_dependencies (); install_names (); print_files () if $verbose; - write_script (\*STDOUT); + if ($run) { + my ($io, $filename) = tempfile ("nswXXXXXX", UNLINK => 1); + write_script ($io); + close $io; + run_makensis ($filename); + } else { + write_script (\*STDOUT); + } } main ()