fix qrc generation for system with symlinks and always build the library

on e.g. macOS symlinks survived the cmake dir copy
and the rcc compiler just did not add the symlinked files

now we handle both symlinks and windows pseudo link files
the same way

always generate the icon library, we will require it
in icon themes to ensure we are no longer missing icons
on foreign desktop envs

ensures that the CI tests the code path we did only
take in the patched craft builds
This commit is contained in:
Christoph Cullmann 2024-05-09 11:28:53 +00:00
parent ae5c4ffb1b
commit f6dd35b261
5 changed files with 79 additions and 113 deletions

View File

@ -64,59 +64,13 @@ add_feature_info("Icon generation" ${WITH_ICON_GENERATION} "for 24x24 and symbol
This feature requires Python 3 and the lxml Python 3 module."
) # The exact amount of indentation used in the line(s) above is intentional
# don't install the individual icons
# useful if you only want to link with the generated icon library
option(SKIP_INSTALL_ICONS "Skip installing the icons files" OFF)
option(ICONS_LIBRARY "Install a library including the breeze & breeze dark icons as resources & functions to use them. This is intended for self contained deployments and should generally not be enabled for systems that have the concept of icon themes like Linux distributions/*BSD" OFF)
if(ICONS_LIBRARY)
find_package(Qt6 NO_MODULE REQUIRED Core)
add_executable(qrcAlias qrcAlias.cpp)
target_link_libraries(qrcAlias PUBLIC Qt6::Core)
function(generate_binary_resource target outfile)
set(RESOURCES_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}/res)
set(RESOURCE_FILE ${RESOURCES_WORKING_DIR}/breeze-${target}.qrc)
set(BINARY_RESOURCE_FILE ${CMAKE_CURRENT_BINARY_DIR}/breeze-${target}.rcc)
# Use $<IF:$<BOOL:${MSVC}>,PATH,LD_LIBRARY_PATH> instead of ${pathVarName} once CMake 3.8 is minimum
if(MSVC)
set(pathVarName PATH)
else()
set(pathVarName LD_LIBRARY_PATH)
endif()
get_target_property(QT_RCC_EXECUTABLE Qt6::rcc LOCATION)
add_custom_target(breeze-${target}-mkdir
COMMAND ${CMAKE_COMMAND} -E make_directory ${RESOURCES_WORKING_DIR}
)
add_custom_command(OUTPUT ${RESOURCE_FILE}
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR} ${RESOURCES_WORKING_DIR}
COMMAND ${CMAKE_COMMAND} -E remove
${RESOURCE_FILE}
${RESOURCE_FILE}.depends
${RESOURCES_WORKING_DIR}/.gitignore
${RESOURCES_WORKING_DIR}/CMakeLists.txt
COMMAND ${QT_RCC_EXECUTABLE} --project -o ${CMAKE_CURRENT_BINARY_DIR}/tmp.qrc
COMMAND ${CMAKE_COMMAND} -E env
${pathVarName}=$<TARGET_FILE_DIR:Qt6::Core>
$<TARGET_FILE:qrcAlias> -i ${CMAKE_CURRENT_BINARY_DIR}/tmp.qrc -o ${RESOURCE_FILE}
WORKING_DIRECTORY ${RESOURCES_WORKING_DIR}
DEPENDS breeze-${target}-mkdir
)
add_custom_command(OUTPUT ${BINARY_RESOURCE_FILE}
COMMAND ${QT_RCC_EXECUTABLE} --binary
-o ${BINARY_RESOURCE_FILE}
${RESOURCE_FILE}
DEPENDS ${RESOURCE_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(breeze-${target}-rcc ALL DEPENDS ${BINARY_RESOURCE_FILE})
set(${outfile} ${BINARY_RESOURCE_FILE} PARENT_SCOPE)
endfunction()
endif()
find_package(Qt6 NO_MODULE REQUIRED Core)
add_executable(qrcAlias qrcAlias.cpp)
target_link_libraries(qrcAlias PUBLIC Qt6::Core)
if(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING)
# validate
@ -158,26 +112,23 @@ install(FILES
)
ecm_setup_version(PROJECT
VARIABLE_PREFIX BREEZEICONS
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/breezeicons_version.h
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6BreezeIconsConfigVersion.cmake"
SOVERSION 6)
VARIABLE_PREFIX BREEZEICONS
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/breezeicons_version.h
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6BreezeIconsConfigVersion.cmake"
SOVERSION 6)
# shall we create a library with the icons?
if(ICONS_LIBRARY)
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
install(EXPORT KF6BreezeIconsTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
FILE KF6BreezeIconsTargets.cmake
NAMESPACE KF6::
)
install(EXPORT KF6BreezeIconsTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
FILE KF6BreezeIconsTargets.cmake
NAMESPACE KF6::
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/breezeicons_version.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/BreezeIcons COMPONENT Devel)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/breezeicons_version.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/BreezeIcons COMPONENT Devel)
add_subdirectory(src)
endif()
add_subdirectory(src)
include(ECMFeatureSummary)
ecm_feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES INCLUDE_QUIET_PACKAGES)

View File

@ -1,7 +1,5 @@
@PACKAGE_INIT@
if(@ICONS_LIBRARY@)
include(CMakeFindDependencyMacro)
find_dependency(Qt6Gui "@REQUIRED_QT_VERSION@")
include("${CMAKE_CURRENT_LIST_DIR}/KF6BreezeIconsTargets.cmake")
endif()
include(CMakeFindDependencyMacro)
find_dependency(Qt6Gui "@REQUIRED_QT_VERSION@")
include("${CMAKE_CURRENT_LIST_DIR}/KF6BreezeIconsTargets.cmake")

View File

@ -1,7 +1,3 @@
if(ICONS_LIBRARY)
generate_binary_resource(icons binary_resource)
endif()
########### install files ###############
FILE(GLOB possible_icon_dirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)

View File

@ -19,6 +19,8 @@
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QRegularExpression>
@ -28,13 +30,12 @@ static QString link(const QString &path, const QString &fileName)
{
QFile in(path + QLatin1Char('/') + fileName);
if (!in.open(QIODevice::ReadOnly)) {
qWarning() << "failed to read" << path << fileName << in.fileName();
qFatal() << "failed to open" << path << fileName << in.fileName();
return QString();
}
QString firstLine = QString::fromLocal8Bit(in.readLine());
if (firstLine.isEmpty()) {
qWarning() << in.fileName() << "line could not be read...";
return QString();
}
QRegularExpression fNameReg(QStringLiteral("(.*\\.(?:svg|png|gif|ico))$"));
@ -53,43 +54,55 @@ static QString link(const QString &path, const QString &fileName)
return path + QLatin1Char('/') + match.captured(1);
}
static int parseFile(const QString &infile, const QString &outfile)
static int parseFile(const QString &indir, const QString &outfile)
{
QFile in(infile);
QFile out(outfile);
QRegularExpression imageReg(QStringLiteral("<file>(.*\\.(?:svg|png|gif|ico))</file>"));
if (!in.open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open" << infile;
return -1;
}
if (!out.open(QIODevice::WriteOnly)) {
qWarning() << "Failed to create" << outfile;
return -2;
qFatal() << "Failed to create" << outfile;
}
out.write("<!DOCTYPE RCC><RCC version=\"1.0\">\n");
out.write("<qresource>\n");
// go to input dir to have proper relative paths
if (!QDir::setCurrent(indir)) {
qFatal() << "Failed to switch to input directory" << indir;
}
while (in.bytesAvailable()) {
QString line = QString::fromLocal8Bit(in.readLine());
QRegularExpressionMatch match = imageReg.match(line);
if (!match.hasMatch()) {
// qDebug() << "No Match: " << line;
out.write(qPrintable(line));
continue;
// we look at all interesting files in the indir and create a qrc with resolved symlinks
QDirIterator it(QStringLiteral("."),
{QStringLiteral("*.theme"), QStringLiteral("*.svg"), QStringLiteral("*.png"), QStringLiteral("*.gif"), QStringLiteral("*.ico")},
QDir::Files,
QDirIterator::Subdirectories);
while (it.hasNext()) {
// ensure nice path without ./ and Co.
const auto file = QDir::current().relativeFilePath(it.next());
const QFileInfo fileInfo(file);
// real symlink resolving for Unices, the rcc compiler ignores such files in -project mode
if (fileInfo.isSymLink()) {
const auto linkPath = fileInfo.canonicalFilePath();
if (linkPath.isEmpty()) {
qFatal() << "Broken symlink" << file << "in input directory" << indir;
}
QString newLine = QStringLiteral(" <file alias=\"%1\">%2</file>\n").arg(file, QDir::current().relativeFilePath(linkPath));
out.write(newLine.toUtf8());
}
QFileInfo info(match.captured(1));
QString aliasLink = link(info.path(), info.fileName());
if (aliasLink.isEmpty()) {
// qDebug() << "No alias: " << line;
out.write(qPrintable(line));
continue;
// pseudo link files generated by Git on Windows
else if (const auto aliasLink = link(fileInfo.path(), fileInfo.fileName()); !aliasLink.isEmpty()) {
QString newLine = QStringLiteral(" <file alias=\"%1\">%2</file>\n").arg(file, QDir::current().relativeFilePath(aliasLink));
out.write(newLine.toUtf8());
}
QString newLine = QStringLiteral("<file alias=\"%1\">%2</file>\n").arg(match.captured(1), aliasLink);
// qDebug() << newLine;
out.write(qPrintable(newLine));
// normal file
else {
QString newLine = QStringLiteral(" <file>%1</file>\n").arg(file);
out.write(newLine.toUtf8());
}
}
out.write("</qresource>\n");
out.write("</RCC>\n");
return 0;
}
@ -99,13 +112,9 @@ int main(int argc, char *argv[])
QCommandLineParser parser;
QCommandLineOption inOption(QStringList() << QLatin1String("i") << QLatin1String("infile"), QStringLiteral("Input qrc file"), QStringLiteral("infile"));
QCommandLineOption inOption(QStringList() << QLatin1String("i") << QLatin1String("indir"), QStringLiteral("Input directory"), QStringLiteral("indir"));
QCommandLineOption outOption(QStringList() << QLatin1String("o") << QLatin1String("outfile"), QStringLiteral("Output qrc file"), QStringLiteral("outfile"));
parser.setApplicationDescription(
QLatin1String("On Windows git handles symbolic links by converting them "
"to text files containing the links to the actual file. This application "
"takes a .qrc file as input and outputs a .qrc file with the symbolic "
"links converted to qrc-aliases."));
parser.setApplicationDescription(QLatin1String("Create a resource file from the given input directory handling symlinks and pseudo symlink files."));
parser.addHelpOption();
parser.addVersionOption();
parser.addOption(inOption);
@ -114,6 +123,5 @@ int main(int argc, char *argv[])
const QString inName = parser.value(inOption);
const QString outName = parser.value(outOption);
return parseFile(inName, outName);
}

View File

@ -1,8 +1,21 @@
# helper functions to ensure we load the icon theme
set(kbreezeicons_SRCS breezeicons.cpp)
# generate resource file for all breeze icons
set(ICON_SRC_DIR ${CMAKE_SOURCE_DIR}/icons)
set(RESOURCES_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}/res)
set(RESOURCE_FILE ${RESOURCES_WORKING_DIR}/breeze-icons.qrc)
# we only will use the normal icons, we do recoloring later
add_custom_command(OUTPUT ${RESOURCE_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${RESOURCES_WORKING_DIR}
COMMAND ${CMAKE_COMMAND} -E copy_directory ${ICON_SRC_DIR} ${RESOURCES_WORKING_DIR}
COMMAND qrcAlias -i ${ICON_SRC_DIR} -o ${RESOURCE_FILE}
DEPENDS qrcAlias
)
qt_add_big_resources(kbreezeicons_resource_SRCS
${CMAKE_BINARY_DIR}/icons/res/breeze-icons.qrc
${RESOURCE_FILE}
OPTIONS --root /icons/breeze
)