Commit 11490810 authored by Michael Pyne's avatar Michael Pyne

Add support for building Qt5 modules.

This commit adds basic support for building Qt5 using the Qt5 support
documented at https://wiki.qt.io/Building_Qt_5_from_Git as requested in
issue #16 (and a dependency for #15).

Architecturally within kdesrc-build, Qt5 is handled as a special type of
module-set, in the same way that KDE project modules are special-cased
using 'kde-projects'. For Qt5, we use 'qt-projects', and reuse the
existing use-modules and ignore-modules options.

The first difference is that {use,ignore}-modules applies to Qt's git
*submodules*. We pass the combination of those to Qt's `init-repository`
script as a module-subset. Currently the user will need to enter at
least a use-modules declaration for other reasons, so we would want to
setup a sample qt5 configuration to include something appropriate.

Qt5 support also involves a dedicated source code updater (based on the
basic Git support already present) and a dedicated build system. The
source code updater handles the Git update for the qt5 "supermodule"
containing `init-repository` and then calls `init-repository` to
complete the rest of the process.

Unfortunately the existing async IPC code doesn't play well with this
but the worst that happens is that kdesrc-build will have 2 updates
running at once for a time (kdesrc-build will think all of Qt is updated
once the supermodule is updated).

The build system is actually fairly standard compared to the other
changes.

There's a lot that's still missing here, including:

* documentation,
* real support for Git submodules (an open feature request for a long
time),
* the per-distro list of Qt build dependencies not handled by
kdesrc-build, and
* support for things like Qt's `qt5_tool`.

But, it's successfully built for me with Qt 5.12. :)
parent 34cef6ec
Pipeline #858 passed with stage
in 1 minute and 3 seconds
......@@ -62,6 +62,7 @@ if (KDESRC_BUILD_INSTALL_MODULES)
modules/ksb/BuildSystem/KDE4.pm
modules/ksb/BuildSystem/QMake.pm
modules/ksb/BuildSystem/Qt4.pm
modules/ksb/BuildSystem/Qt5.pm
DESTINATION ${KDESRC_BUILD_MODULE_INSTALL_PREFIX}/ksb/BuildSystem)
install(FILES
......@@ -71,6 +72,7 @@ if (KDESRC_BUILD_INSTALL_MODULES)
install(FILES
modules/ksb/ModuleSet/KDEProjects.pm
modules/ksb/ModuleSet/Null.pm
modules/ksb/ModuleSet/Qt.pm
DESTINATION ${KDESRC_BUILD_MODULE_INSTALL_PREFIX}/ksb/ModuleSet)
install(FILES
......@@ -84,6 +86,7 @@ if (KDESRC_BUILD_INSTALL_MODULES)
modules/ksb/Updater/KDEProject.pm
modules/ksb/Updater/KDEProjectMetadata.pm
modules/ksb/Updater/Svn.pm
modules/ksb/Updater/Qt5.pm
DESTINATION ${KDESRC_BUILD_MODULE_INSTALL_PREFIX}/ksb/Updater)
endif()
......@@ -93,6 +96,8 @@ install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/kdesrc-build-setup DESTINATION ${KD
install(PROGRAMS
${CMAKE_SOURCE_DIR}/sample-kde-env-master.sh
${CMAKE_SOURCE_DIR}/sample-xsession.sh
${CMAKE_SOURCE_DIR}/custom-qt5-libs-build-include
${CMAKE_SOURCE_DIR}/qt5-build-include
${CMAKE_SOURCE_DIR}/kf5-applications-build-include
${CMAKE_SOURCE_DIR}/kf5-extragear-build-include
${CMAKE_SOURCE_DIR}/kf5-frameworks-build-include
......
......@@ -2,7 +2,7 @@
# Script to create a configuration file for kdesrc-build.
#
# Copyright © 2011, 2016 Michael Pyne. <mpyne@kde.org>
# Copyright © 2011, 2019 Michael Pyne. <mpyne@kde.org>
# Home page: https://kdesrc-build.kde.org/
#
# This program is free software; you can redistribute it and/or modify it under
......@@ -266,12 +266,14 @@ else {
my @chosenModules = getListOptions(
"Which major module groups do you want to build?",
[
qt5 => 'Qt 5 - Base support libraries (required unless distro supplies)',
frameworks => 'KDE Frameworks 5 - Essential libraries/runtime (required)',
workspace => 'KDE Plasma 5 Desktop and workspace',
base => 'Assorted useful KF5-based applications',
pim => 'Personal Information Management software',
],
{
qt5 => 1,
frameworks => 1,
workspace => 1,
base => 1,
......@@ -335,17 +337,21 @@ EOF
print $output <<EOF;
# Autogenerated by kdesrc-build-setup. You may modify this file if desired.
global
EOF
print $output <<EOF;
# This option is used to switch development tracks for many modules at
# once. 'kf5-qt5' is the latest KF5 and Qt5-based software.
branch-group kf5-qt5
# Only set qtdir if we're building it ourselves. If user uses their own custom
# Qt they should already be setting PATH and in that case we need do nothing
# anyways.
if (grep /^qt5$/, @chosenModules) {
print $output <<EOF;
# The path to your Qt installation (default is empty, assumes Qt provided
# by system)
# qtdir ~/qt5
qtdir ~/kde/qt5
EOF
}
print $output <<EOF;
# Finds and includes *KDE*-based dependencies into the build. This makes
# it easier to ensure that you have all the modules needed, but the
......@@ -418,6 +424,19 @@ if (! -e "$basedir/kf5-frameworks-build-include") {
}
}
if (grep /^qt5$/, @chosenModules) {
print $output <<EOF;
# Refers to the qt5 file included as part of kdesrc-build. The file
# is simply read-in at this point as if you'd typed it in yourself.
include $basedir/qt5-build-include
# Support libraries that use Qt5
include $basedir/custom-qt5-libs-build-include
EOF
}
if (grep /^frameworks$/, @chosenModules) {
print $output <<EOF;
......
......@@ -20,6 +20,7 @@ use ksb::Module;
use ksb::ModuleResolver 0.20;
use ksb::ModuleSet 0.20;
use ksb::ModuleSet::KDEProjects;
use ksb::ModuleSet::Qt;
use ksb::OSSupport;
use ksb::RecursiveFH;
use ksb::DependencyResolver 0.20;
......@@ -41,7 +42,8 @@ use IO::Select;
use constant {
# We use a named remote to make some git commands work that don't accept the
# full path.
KDE_PROJECT_ID => 'kde-projects', # git-repository-base for kde_projects.xml
KDE_PROJECT_ID => 'kde-projects', # git-repository-base for sysadmin/repo-metadata
QT_PROJECT_ID => 'qt-projects', # git-repository-base for qt.io Git repo
};
### Package methods
......@@ -868,7 +870,7 @@ EOF
}
my $repoSet = $ctx->getOption('git-repository-base');
if ($selectedRepo ne KDE_PROJECT_ID &&
if ($selectedRepo ne KDE_PROJECT_ID && $selectedRepo ne QT_PROJECT_ID &&
not exists $repoSet->{$selectedRepo})
{
my $projectID = KDE_PROJECT_ID;
......@@ -992,13 +994,13 @@ sub _parseModuleSetOptions
$moduleSet = _parseModuleOptions($ctx, $fileReader, $moduleSet, qr/^end\s+module(-?set)?$/);
if ($moduleSet->getOption('repository') eq KDE_PROJECT_ID &&
!$moduleSet->isa('ksb::ModuleSet::KDEProjects'))
{
# Perl-specific note! re-blessing the module set into the right 'class'
# You'd probably have to construct an entirely new object and copy the
# members over in other languages.
# Perl-specific note! re-blessing the module set into the right 'class'
# You'd probably have to construct an entirely new object and copy the
# members over in other languages.
if ($moduleSet->getOption('repository') eq KDE_PROJECT_ID) {
bless $moduleSet, 'ksb::ModuleSet::KDEProjects';
} elsif ($moduleSet->getOption('repository') eq QT_PROJECT_ID) {
bless $moduleSet, 'ksb::ModuleSet::Qt';
}
return $moduleSet;
......
package ksb::BuildSystem::Qt5 0.10;
# Build system for the Qt5 toolkit
use strict;
use warnings;
use 5.014;
use ksb::BuildException;
use ksb::BuildSystem;
use ksb::Debug;
use ksb::Util;
use parent qw(ksb::BuildSystem);
# OVERRIDE
sub configuredModuleFileName
{
return 'Makefile';
}
# OVERRIDE
sub name
{
return 'Qt5';
}
# Return value style: boolean
sub configureInternal
{
my $self = assert_isa(shift, __PACKAGE__);
my $module = $self->module();
my $srcdir = $module->fullpath('source');
my $script = "$srcdir/configure";
if (! -e $script && !pretending())
{
error ("\tMissing configure script for r[b[$module]");
return 0;
}
my @commands = split (/\s+/, $module->getOption('configure-flags'));
push @commands, qw(-confirm-license -opensource -nomake examples -nomake tests);
# Get the user's CXXFLAGS
my $cxxflags = $module->getOption('cxxflags');
$module->buildContext()->queueEnvironmentVariable('CXXFLAGS', $cxxflags);
my $prefix = $module->getOption('prefix');
my $qtdir = $module->getOption('qtdir');
if ($prefix && $qtdir && $prefix ne $qtdir) {
warning (<<EOF);
b[y[*]
b[y[*] Building the Qt module, but the install directory for Qt is not set to the
b[y[*] Qt directory to use.
b[y[*] install directory ('prefix' option): b[$prefix]
b[y[*] Qt install to use ('qtdir' option): b[$qtdir]
b[y[*]
b[y[*] Try setting b[qtdir] to the same setting as the Qt module's b[prefix].
b[y[*]
EOF
}
$prefix ||= $qtdir; # Use qtdir for install if prefix not set
# Some users have added -prefix manually to their flags, they
# probably shouldn't anymore. :)
if (grep /^-prefix(=.*)?$/, @commands) {
warning (<<EOF);
b[y[*]
b[y[*] You have the y[-prefix] option selected in your $module configure flags.
b[y[*] kdesrc-build will correctly add the -prefix option to match your Qt
b[y[*] directory setting, so you do not need to use -prefix yourself.
b[y[*]
EOF
}
push @commands, "-prefix", $prefix;
unshift @commands, $script;
my $builddir = $module->fullpath('build');
my $old_flags = $module->getPersistentOption('last-configure-flags') || '';
my $cur_flags = get_list_digest(@commands);
if(($cur_flags ne $old_flags) ||
($module->getOption('reconfigure')) ||
1 || # TODO: Find a safe way to skip reconfiguration
(! -e "$builddir/Makefile")
)
{
note ("\tb[r[LGPL license selected for Qt]. See $srcdir/LICENSE.LGPL");
info ("\tRunning g[configure]...");
$module->setPersistentOption('last-configure-flags', $cur_flags);
return log_command($module, "configure", \@commands) == 0;
}
# Skip execution of configure.
return 1;
}
1;
......@@ -130,8 +130,8 @@ DONE
_throw("Embedded sample file missing!");
my $numCpus = `nproc 2>/dev/null` || 4;
$sampleRc =~ s/%\{num_cpus}/$numCpus/;
$sampleRc =~ s/%\{base_dir}/$baseDir/;
$sampleRc =~ s/%\{num_cpus}/$numCpus/g;
$sampleRc =~ s/%\{base_dir}/$baseDir/g;
open my $sampleFh, '>', "$ENV{HOME}/.kdesrc-buildrc"
or _throw("Couldn't open new ~/.kdesrc-buildrc: $!");
......@@ -310,20 +310,20 @@ dnf -y install
# List of all options: https://go.kde.org/u/ksboptions
global
branch-group kf5-qt5
kdedir ~/kde-5 # Where to install KF5-based software
# Uncomment this and edit value to choose a different Qt5
# qtdir /usr # Where to find Qt5
# Paths
kdedir ~/kde/usr # Where to install KF5-based software
qtdir ~/kde/qt5 # Where to find Qt5
source-dir ~/kde/src # Where sources are downloaded
build-dir ~/kde/build # Where the source build is run
ignore-kde-structure true # Use flat structure
# Will pull in KDE-based dependencies only, to save you the trouble of
# listing them all below
include-dependencies true
source-dir ~/kde/src
build-dir ~/kde/build
ignore-kde-structure true
cmake-options -DCMAKE_BUILD_TYPE=RelWithDebInfo
make-options -j%{num_cpus}
end global
......@@ -336,6 +336,11 @@ end global
# You can include other files inline using the "include" command. We do this here
# to include files which are updated with kdesrc-build.
# Qt and some Qt-using middleware libraries
include %{base_dir}/qt5-build-include
include %{base_dir}/custom-qt5-libs-build-include
# KF5 and Plasma :)
include %{base_dir}/kf5-qt5-build-include
# To change options for modules that have already been defined, use an
......@@ -343,4 +348,3 @@ include %{base_dir}/kf5-qt5-build-include
options kcoreaddons
make-options -j4
end options
......@@ -23,6 +23,7 @@ use ksb::Updater::Git;
use ksb::Updater::Bzr;
use ksb::Updater::KDEProject;
use ksb::Updater::KDEProjectMetadata;
use ksb::Updater::Qt5;
use ksb::BuildException 0.20;
......@@ -30,6 +31,7 @@ use ksb::BuildSystem 0.30;
use ksb::BuildSystem::Autotools;
use ksb::BuildSystem::QMake;
use ksb::BuildSystem::Qt4;
use ksb::BuildSystem::Qt5;
use ksb::BuildSystem::KDE4;
use ksb::BuildSystem::CMakeBootstrap;
......@@ -256,6 +258,7 @@ sub setScmType
when('l10n') { $newType = ksb::l10nSystem->new($self); }
when('svn') { $newType = ksb::Updater::Svn->new($self); }
when('bzr') { $newType = ksb::Updater::Bzr->new($self); }
when('qt5') { $newType = ksb::Updater::Qt5->new($self); }
default { $newType = undef; }
}
......@@ -290,6 +293,7 @@ sub buildSystemFromName
'cmake-bootstrap' => 'ksb::BuildSystem::CMakeBootstrap',
'kde' => 'ksb::BuildSystem::KDE4',
'qt' => 'ksb::BuildSystem::Qt4',
'qt5' => 'ksb::BuildSystem::Qt5',
'autotools' => 'ksb::BuildSystem::Autotools',
);
......
package ksb::ModuleSet::Qt 0.10;
# Class: ModuleSet::Qt
#
# This represents a collection of Qt5 source code modules that are collectively
# kept up to date by Qt's init-repository script. This module set is
# essentially uses to make sure that generated ksb::Modules use proper scm()
# and buildSystems()
#
# Use of this module-set is controlled by the 'repository' option being set to
# the magic value 'qt-projects', just as 'kde-projects' is used for KDE.
use strict;
use warnings;
use 5.014;
use parent qw(ksb::ModuleSet);
use ksb::BuildContext;
use ksb::BuildException;
use ksb::BuildSystem::Qt5;
use ksb::Debug;
use ksb::Module;
use ksb::Util;
sub _makeQt5Module
{
my $self = assert_isa(shift, __PACKAGE__);
my $ctx = assert_isa(shift, 'ksb::BuildContext');
my $newModule = ksb::Module->new($ctx, 'qt5');
$self->_initializeNewModule($newModule);
# Repo URL to the Qt5 "supermodule" that contains the documented
# init-repository script.
# See https://wiki.qt.io/Building_Qt_5_from_Git
$newModule->setOption('repository', 'https://code.qt.io/qt/qt5.git');
$newModule->setScmType('qt5');
$newModule->setBuildSystem(ksb::BuildSystem::Qt5->new($newModule));
# Convert the use-modules/ignore-modules entries into a form appropriate
# for init-repository's module-subset option.
my @modEntries = ($self->modulesToFind(), map { "-$_" } $self->modulesToIgnore());
$newModule->setOption('use-qt5-modules', join(' ', @modEntries));
return $newModule;
}
# This function should be called after options are read and build metadata is
# available in order to convert this module set to a list of ksb::Module.
#
# In our case, we will return ONLY ONE MODULE. That module will handle "sub
# modules" via the init-repository script so from kdesrc-build's perspective it
# is handled as a single unit.
#
# OVERRIDE from super class
sub convertToModules
{
my ($self, $ctx) = @_;
return $self->_makeQt5Module($ctx);
}
1;
......@@ -140,34 +140,22 @@ sub _clone
return;
}
# Either performs the initial checkout or updates the current git checkout
# for git-using modules, as appropriate.
#
# If errors are encountered, an exception is raised.
#
# Returns the number of *commits* affected.
sub updateCheckout
# Checks that the required source dir is either not already present or is empty.
# Throws an exception if that's not true.
sub _verifySafeToCloneIntoSourceDir
{
my $self = assert_isa(shift, 'ksb::Updater::Git');
my $module = $self->module();
my $srcdir = $module->fullpath('source');
if (-d "$srcdir/.git") {
# Note that this function will throw an exception on failure.
return $self->updateExistingClone();
}
else {
# Check if an existing source directory is there somehow.
if (-e "$srcdir" && !is_dir_empty($srcdir)) {
if ($module->getOption('#delete-my-patches')) {
warning ("\tRemoving conflicting source directory " .
"as allowed by --delete-my-patches");
warning ("\tRemoving b[$srcdir]");
safe_rmtree($srcdir) or
croak_internal("Unable to delete $srcdir!");
}
else {
error (<<EOF);
my ($module, $srcdir) = @_;
if (-e "$srcdir" && !is_dir_empty($srcdir)) {
if ($module->getOption('#delete-my-patches')) {
warning ("\tRemoving conflicting source directory " .
"as allowed by --delete-my-patches");
warning ("\tRemoving b[$srcdir]");
safe_rmtree($srcdir) or
croak_internal("Unable to delete $srcdir!");
}
else {
error (<<EOF);
The source directory for b[$module] does not exist. kdesrc-build would download
it, except there is already a file or directory present in the desired source
directory:
......@@ -182,14 +170,36 @@ FILES IN THE DIRECTORY.
EOF
if (-e "$srcdir/.svn") {
error ("svn status of $srcdir:");
system('svn', 'st', '--non-interactive', $srcdir);
}
croak_runtime('Conflicting source-dir present');
if (-e "$srcdir/.svn") {
error ("svn status of $srcdir:");
system('svn', 'st', '--non-interactive', $srcdir);
}
croak_runtime('Conflicting source-dir present');
}
}
return;
}
# Either performs the initial checkout or updates the current git checkout
# for git-using modules, as appropriate.
#
# If errors are encountered, an exception is raised.
#
# Returns the number of *commits* affected.
sub updateCheckout
{
my $self = assert_isa(shift, 'ksb::Updater::Git');
my $module = $self->module();
my $srcdir = $module->fullpath('source');
if (-d "$srcdir/.git") {
# Note that this function will throw an exception on failure.
return $self->updateExistingClone();
}
else {
_verifySafeToCloneIntoSourceDir($module, $srcdir);
my $git_repo = $module->getOption('repository');
......
package ksb::Updater::Qt5 0.10;
# Handles updating Qt 5 source code. Requires git but uses Qt 5's dedicated
# 'init-repository' script to keep the source up to date and coherent.
use strict;
use warnings;
use 5.014;
use parent qw(ksb::Updater::Git);
use ksb::BuildException;
use ksb::Debug;
use ksb::IPC::Null;
use ksb::Util;
sub name
{
return 'qt5';
}
# Handles calling init-repository to clone or update the appropriate Qt 5
# submodules.
#
# Returns number of commits updated (or rather, will...)
sub _updateRepository
{
my $self = assert_isa(shift, __PACKAGE__);
my $module = $self->module();
my $srcdir = $module->fullpath('source');
if (!pretending() && (! -e "$srcdir/init-repository" || ! -x _)) {
croak_runtime ("The Qt 5 repository update script could not be found, or is not executable!");
}
p_chdir($srcdir);
# See https://wiki.qt.io/Building_Qt_5_from_Git#Getting_the_source_code for
# why we skip web engine by default. As of 2019-01-12 it is only used for
# PIM or optionally within Plasma
my @modules = split(' ', $module->getOption('use-qt5-modules'));
push @modules, qw(default -qtwebengine)
unless @modules;
my $subset_arg = join(',', @modules);
# -f forces a re-update if necessary
my @command = ("$srcdir/init-repository", '-f', "--module-subset=$subset_arg");
note ("\tUsing Qt 5 modules: ", join(', ', @modules));
if (0 != log_command($module, 'init-repository', \@command)) {
croak_runtime ("Couldn't update Qt 5 repository submodules!");
}
return 1; # TODO: Count commits
}
# Updates an existing Qt5 super module checkout.
# Throws exceptions on failure, otherwise returns number of commits updated
# OVERRIDE from super class
sub updateExistingClone
{
my $self = assert_isa(shift, __PACKAGE__);
# Update init-repository and the shell of the super module itself.
my $count = $self->SUPER::updateExistingClone();
# updateRepository has init-repository work to update the source
return $count + $self->_updateRepository();
}
# Either performs the initial checkout or updates the current git checkout
# for git-using modules, as appropriate.
#
# If errors are encountered, an exception is raised.
#
# Returns the number of *commits* affected.
# OVERRIDE from super class
sub updateCheckout
{
my $self = assert_isa(shift, __PACKAGE__);
my $module = $self->module();
my $srcdir = $module->fullpath('source');
if (-d "$srcdir/.git") {
# Note that this function will throw an exception on failure.
return $self->updateExistingClone();
}
else {
$self->_verifySafeToCloneIntoSourceDir($module, $srcdir);
$self->_clone($module->getOption('repository'));
note ("\tQt update script is installed, downloading remainder of Qt");
note ("\tb[y[THIS WILL TAKE SOME TIME]");
# With the supermodule cloned, we then need to call into
# init-repository to have it complete the checkout.
return $self->_updateRepository(); # num commits
}
return 0; # num commits
}
1;
module-set qt5-set
repository qt-projects
branch 5.11 # not the most recent but recent enough
# init-repository supports catch-alls like "default" as well, in which case
# you will want to uncomment ignore-modules below to control which modules to
# leave out
use-modules qtbase qtdeclarative qtgraphicaleffects qtimageformats \
qtmultimedia qtquickcontrols qtquickcontrols2 qtscript qtsensors qtsvg \
qttools qtwayland qtwebchannel qtwebsockets qtwebview qtx11extras \
qtxmlpatterns
# ignore-modules qtwebengine
# install path. This *MUST* match your qtdir setting in kdesrc-buildrc!
prefix ${qtdir}
configure-flags -optimized-tools -reduce-relocations
# make-options -j7
end module-set
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment