diff --git a/doc/index.docbook b/doc/index.docbook
index dc4827a..52a8634 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -1665,6 +1665,24 @@ only works for qt.
+
+custom-build-command
+Module setting overrides global
+
+ This option can be set to run a different command (other than
+ make, for example) in order to perform the build
+ process. &kdesrc-build; should in general do the right thing, so you
+ should not need to set this option. However it can be useful to use
+ alternate build systems.
+
+
+ The value of this option is used as the command line to run, modified
+ by the make-options option as
+ normal.
+
+
+
+
cxxflagsAppends to global option
diff --git a/kdesrc-build b/kdesrc-build
index 83a9334..c5b4966 100755
--- a/kdesrc-build
+++ b/kdesrc-build
@@ -1528,6 +1528,7 @@ EOF
"cmake-options" => "",
"configure-flags" => "",
"colorful-output" => 1, # Use color by default.
+ "custom-build-command" => '',
"cxxflags" => "-pipe",
"debug" => "",
"debug-level" => ksb::Debug::INFO,
@@ -3866,6 +3867,8 @@ EOF
ksb::Debug->import();
ksb::Util->import();
+ use List::Util qw(first);
+
sub new
{
my ($class, $module) = @_;
@@ -3948,12 +3951,21 @@ EOF
return 'generic';
}
+ # Returns a list of possible build commands to run, any one of which should
+ # be supported by the build system.
+ sub buildCommands
+ {
+ # Non Linux systems can sometimes fail to build when GNU Make would work,
+ # so prefer GNU Make if present, otherwise try regular make.
+ return 'gmake', 'make';
+ }
+
# Return value style: boolean
sub buildInternal
{
my $self = shift;
- return main::safe_make($self->module(), {
+ return $self->safe_make({
target => undef,
message => 'Compiling...',
'make-options' => [
@@ -4005,7 +4017,7 @@ EOF
my $module = $self->module();
my @cmdPrefix = @_;
- return main::safe_make ($module, {
+ return $self->safe_make ({
target => 'install',
message => "Installing g[$module]",
'prefix-options' => [@cmdPrefix],
@@ -4022,7 +4034,7 @@ EOF
my $module = $self->module();
my @cmdPrefix = @_;
- return main::safe_make ($module, {
+ return $self->safe_make ({
target => 'uninstall',
message => "Uninstalling g[$module]",
'prefix-options' => [@cmdPrefix],
@@ -4089,6 +4101,198 @@ EOF
return 1;
}
+ # Subroutine to run the build command with the arguments given by the
+ # passed hash.
+ #
+ # In addition to finding the proper executable, this function handles the
+ # step of running the build command for individual subdirectories (as
+ # specified by the checkout-only option to the module). Due to the various
+ # ways the build command is called by this script, it is required to pass
+ # customization options in a hash:
+ # {
+ # target => undef, or a valid build target e.g. 'install',
+ # message => 'Compiling.../Installing.../etc.'
+ # make-options => [ list of command line arguments to pass to make. See
+ # make-options ],
+ # prefix-options => [ list of command line arguments to prefix *before* the
+ # make command, used for make-install-prefix support for
+ # e.g. sudo ],
+ # logbase => 'base-log-filename',
+ # subdirs => [ list of subdirectories of the module to build,
+ # relative to the module's own build directory. ]
+ # }
+ #
+ # target and message are required. logbase is required if target is left
+ # undefined, but otherwise defaults to the same value as target.
+ #
+ # Note that the make command is based on the results of the 'buildCommands'
+ # subroutine which should be overridden if necessary by subclasses. Each
+ # command should be the command name (i.e. no path). The user may override
+ # the command used (for build only) by using the 'custom-build-command'
+ # option.
+ #
+ # The first command name found which resolves to an executable on the
+ # system will be used, if no command this function will fail.
+ #
+ # The first argument should be the Module object to be made.
+ # The second argument should be the reference to the hash described above.
+ #
+ # Returns 0 on success, non-zero on failure (shell script style)
+ sub safe_make (@)
+ {
+ my ($self, $optsRef) = @_;
+ assert_isa($self, 'GenericBuildSystem');
+ my $module = $self->module();
+
+ # Convert the path to an absolute path since I've encountered a sudo
+ # that is apparently unable to guess. Maybe it's better that it
+ # doesn't guess anyways from a security point-of-view.
+ my $buildCommand = first { absPathToExecutable($_) } $self->buildCommands();
+ my @buildCommandLine = $buildCommand;
+
+ # Check for custom user command. We support command line options being
+ # passed to the command as well.
+ my $userCommand = $module->getOption('custom-build-command');
+ if ($userCommand) {
+ @buildCommandLine = split_quoted_on_whitespace($userCommand);
+ $buildCommand = absPathToExecutable($buildCommandLine[0]);
+ }
+
+ if (!$buildCommand) {
+ $buildCommand = $userCommand || $self->buildCommands();
+ error (" r[b[*] Unable to find the g[$buildCommand] executable!");
+ return 1;
+ }
+
+ # Make it prettier if pretending (Remove leading directories).
+ $buildCommand =~ s{^/.*/}{} if pretending();
+ shift @buildCommandLine; # $buildCommand is already the first entry.
+
+ # Simplify code by forcing lists to exist.
+ $optsRef->{'prefix-options'} //= [ ];
+ $optsRef->{'make-options'} //= [ ];
+ $optsRef->{'subdirs'} //= [ ];
+
+ my @prefixOpts = @{$optsRef->{'prefix-options'}};
+
+ # If using sudo ensure that it doesn't wait on tty, but tries to read from
+ # stdin (which should fail as we redirect that from /dev/null)
+ if (@prefixOpts && $prefixOpts[0] eq 'sudo' && !grep { /^-S$/ } @prefixOpts)
+ {
+ splice (@prefixOpts, 1, 0, '-S'); # Add -S right after 'sudo'
+ }
+
+ # Assemble arguments
+ my @args = (@prefixOpts, $buildCommand, @buildCommandLine);
+ push @args, $optsRef->{target} if $optsRef->{target};
+ push @args, @{$optsRef->{'make-options'}};
+
+ info ("\t", $optsRef->{message});
+
+ # Here we're attempting to ensure that we either run the build command
+ # in each subdirectory, *or* for the whole module, but not both.
+ my @dirs = @{$optsRef->{subdirs}};
+ push (@dirs, "") if scalar @dirs == 0;
+
+ for my $subdir (@dirs)
+ {
+ # Some subdirectories shouldn't have the build command run within
+ # them.
+ next unless $self->isSubdirBuildable($subdir);
+
+ my $logname = $optsRef->{logbase} // $optsRef->{target};
+
+ if ($subdir ne '')
+ {
+ $logname = $logname . "-$subdir";
+
+ # Remove slashes in favor of something else.
+ $logname =~ tr{/}{-};
+
+ # Mention subdirectory that we're working on, move ellipsis
+ # if present.
+ my $subdirMessage = $optsRef->{message};
+ if ($subdirMessage =~ /\.\.\.$/) {
+ $subdirMessage =~ s/(\.\.\.)?$/ subdirectory g[$subdir]$1/;
+ }
+ info ("\t$subdirMessage");
+ }
+
+ my $builddir = $module->fullpath('build') . "/$subdir";
+ $builddir =~ s/\/*$//; # Remove trailing /
+
+ p_chdir ($builddir);
+
+ my $result = $self->runBuildCommand($logname, \@args);
+ return $result if $result;
+ };
+
+ return 0;
+ }
+
+ # Subroutine to run make and process the build process output in order to
+ # provide completion updates. This procedure takes the same arguments as
+ # log_command() (described here as well), except that the callback argument
+ # is not used.
+ #
+ # First parameter is the name of the log file to use (relative to the log
+ # directory).
+ # Second parameter is a reference to an array with the command and its
+ # arguments. i.e. ['command', 'arg1', 'arg2']
+ # The return value is the shell return code, so 0 is success, and non-zero
+ # is failure.
+ sub runBuildCommand
+ {
+ my ($self, $filename, $argRef) = @_;
+ assert_isa($self, 'GenericBuildSystem');
+ my $module = $self->module();
+
+ # There are situations when we don't want (or can't get) progress output:
+ # 1. Not using CMake (i.e. Qt)
+ # 2. If we're not printing to a terminal.
+ # 3. When we're debugging (we'd interfere with debugging output).
+ if (!$self->isProgressOutputSupported() || ! -t STDERR || debugging())
+ {
+ return log_command($module, $filename, $argRef);
+ }
+
+ # Setup callback function for use by log_command.
+ my $last = -1;
+
+ # w00t. Check out the closure! Maks would be so proud.
+ my $log_command_callback = sub {
+ my ($input) = shift;
+
+ if (not defined $input)
+ {
+ # End of input, cleanup.
+ print STDERR "\r\e[K";
+ }
+ else
+ {
+ chomp($input);
+
+ my $percentage = '';
+
+ if ($input =~ /^\[\s*([0-9]+)%]/)
+ {
+ $percentage = $1;
+ }
+
+ # Update terminal (\e[K clears to the end of line) if the
+ # percentage changed.
+ if ($percentage and $percentage ne $last)
+ {
+ print STDERR "\r$percentage% \e[K";
+ }
+
+ $last = $percentage;
+ }
+ };
+
+ return log_command($module, $filename, $argRef, { callback => $log_command_callback });
+ }
+
1;
}
# }}}
@@ -4261,7 +4465,7 @@ EOF
my @langs = $self->languages();
my $result = 0;
- $result = (main::safe_make($self->module(), {
+ $result = ($self->safe_make({
target => undef,
message => "Building localization for language...",
logbase => "build",
@@ -4297,7 +4501,7 @@ EOF
my $builddir = $self->module()->fullpath('build');
my @langs = $self->languages();
- return (main::safe_make($self->module(), {
+ return ($self->safe_make({
target => 'install',
message => "Installing language...",
logbase => "install",
@@ -5905,71 +6109,6 @@ sub download_file
return 0;
}
-# Subroutine to run make and process the build process output in order to
-# provide completion updates. This procedure takes the same arguments as
-# log_command() (described here as well), except that the callback argument is
-# not used.
-#
-# First parameter is the Module being built (for logging purposes and such).
-# Second parameter is the name of the log file to use (relative to the log
-# directory).
-# Third parameter is a reference to an array with the command and its
-# arguments. i.e. ['command', 'arg1', 'arg2']
-# The return value is the shell return code, so 0 is success, and non-zero is
-# failure.
-sub run_make_command
-{
- my ($module, $filename, $argRef) = @_;
- assert_isa($module, 'Module');
-
- debug ("run_make_command: $module, ", join(', ', @{$argRef}));
-
- # There are situations when we don't want (or can't get) progress output:
- # 1. Not using CMake (i.e. Qt)
- # 2. If we're not printing to a terminal.
- # 3. When we're debugging (we'd interfere with debugging output).
- if (!$module->buildSystem()->isProgressOutputSupported() || ! -t STDERR || debugging())
- {
- return log_command($module, $filename, $argRef);
- }
-
- # Setup callback function for use by log_command.
- my $last = -1;
-
- # w00t. Check out the closure! Maks would be so proud.
- my $log_command_callback = sub {
- my ($input) = shift;
-
- if (not defined $input)
- {
- # End of input, cleanup.
- print STDERR "\r\e[K";
- }
- else
- {
- chomp($input);
-
- my $percentage = '';
-
- if ($input =~ /^\[\s*([0-9]+)%]/)
- {
- $percentage = $1;
- }
-
- # Update terminal (\e[K clears to the end of line) if the
- # percentage changed.
- if ($percentage and $percentage ne $last)
- {
- print STDERR "\r$percentage% \e[K";
- }
-
- $last = $percentage;
- }
- };
-
- return log_command($module, $filename, $argRef, { callback => $log_command_callback });
-}
-
# Subroutine to delete a directory and all files and subdirectories within.
# Does nothing in pretend mode. An analogue to "rm -rf" from Linux.
# Requires File::Find module.
@@ -6030,113 +6169,6 @@ sub safe_rmtree
return 1;
}
-# Subroutine to run the make command with the arguments given by the passed
-# hash. In addition to finding the proper make executable, this function
-# handles the step of running make for individual subdirectories (as specified
-# by the checkout-only option to the module). Due to the various ways make is
-# used by this script, it is required to pass customization options in a hash:
-# {
-# target => undef, or a valid make target e.g. 'install',
-# message => 'Compiling.../Installing.../etc.'
-# make-options => [ list of command line arguments to pass to make. See
-# make-options ],
-# prefix-options => [ list of command line arguments to prefix *before* the
-# make command, used for make-install-prefix support for
-# e.g. sudo ],
-# logbase => 'base-log-filename',
-# subdirs => [ list of subdirectories of the module to build,
-# relative to the module's own build directory. ]
-# }
-#
-# target and message are required. logbase is required if target is left
-# undefined, but otherwise defaults to the same value as target.
-#
-# The first argument should be the Module object to be made.
-# The second argument should be the reference to the hash described above.
-#
-# Returns 0 on success, non-zero on failure (shell script style)
-sub safe_make (@)
-{
- my ($module, $optsRef) = @_;
- assert_isa($module, 'Module');
-
- # Non Linux systems can sometimes fail to build when GNU Make would work,
- # so prefer GNU Make if present, otherwise try regular make. Also, convert
- # the path to an absolute path since I've encountered a sudo that is
- # apparently unable to guess. Maybe it's better that it doesn't guess
- # anyways from a security point-of-view.
- my $make;
- if(!($make = absPathToExecutable('gmake') || absPathToExecutable('make'))) {
- # Weird, we can't find make, you'd think configure would have
- # noticed...
- error (" r[b[*] Unable to find the g[make] executable!");
- return 1;
- }
-
- # Make it prettier if pretending (Remove leading directories).
- $make =~ s{^/.*/}{} if pretending();
-
- # Simplify code by forcing lists to exist.
- $optsRef->{'prefix-options'} //= [ ];
- $optsRef->{'make-options'} //= [ ];
- $optsRef->{'subdirs'} //= [ ];
-
- my @prefixOpts = @{$optsRef->{'prefix-options'}};
-
- # If using sudo ensure that it doesn't wait on tty, but tries to read from
- # stdin (which should fail as we redirect that from /dev/null)
- if (@prefixOpts && $prefixOpts[0] eq 'sudo' && !grep { /^-S$/ } @prefixOpts)
- {
- splice (@prefixOpts, 1, 0, '-S'); # Add -S right after 'sudo'
- }
-
- # Assemble arguments
- my @args = (@prefixOpts, $make);
- push @args, $optsRef->{target} if $optsRef->{target};
- push @args, @{$optsRef->{'make-options'}};
-
- info ("\t", $optsRef->{message});
-
- # Here we're attempting to ensure that we either run make in each
- # subdirectory, *or* for the whole module, but not both.
- my @dirs = @{$optsRef->{subdirs}};
- push (@dirs, "") if scalar @dirs == 0;
-
- for my $subdir (@dirs)
- {
- # Some subdirectories shouldn't have make run within them.
- next unless $module->buildSystem()->isSubdirBuildable($subdir);
-
- my $logname = $optsRef->{logbase} // $optsRef->{target};
-
- if ($subdir ne '')
- {
- $logname = $logname . "-$subdir";
-
- # Remove slashes in favor of something else.
- $logname =~ tr{/}{-};
-
- # Mention subdirectory that we're working on, move ellipsis
- # if present.
- my $subdirMessage = $optsRef->{message};
- if ($subdirMessage =~ /\.\.\.$/) {
- $subdirMessage =~ s/(\.\.\.)?$/ subdirectory g[$subdir]$1/;
- }
- info ("\t$subdirMessage");
- }
-
- my $builddir = $module->fullpath('build') . "/$subdir";
- $builddir =~ s/\/*$//; # Remove trailing /
-
- p_chdir ($builddir);
-
- my $result = run_make_command ($module, $logname, \@args);
- return $result if $result;
- };
-
- return 0;
-}
-
# Reads a "line" from a file. This line is stripped of comments and extraneous
# whitespace. Also, backslash-continued multiple lines are merged into a single
# line.