From fff3101bc6bbb2f8433c7edde80f77b6efb0ec39 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 2 Jun 2015 11:42:07 -0700 Subject: Place classes from private headers in the Qt_5_PRIVATE_API ELF version This way, it's possible to tell which applications and libraries depend on the Qt private API and of which Qt library. Linux distributions can use this information to decide which applications need to be recompiled every time Qt itself is rebuilt. This is done by scanning all class and struct definitions in the private headers (we've already got the list from syncqt). I opted to add a new script instead of modifying syncqt because then this can run in parallel with the rest of the compilation, as opposed to during qmake time. Another advantage is that it catches modifications to the headers in between qmake executions. Since this is already Unix specific, it should be no problem to use Perl. This solution is limited to use of non-inline symbols of classes declared in private headers. It will not catch free variables (such as qsimd_p.h's qt_cpu_features), use of inlined functions or just plain use of a class/struct for accessing its data members. However, this is already better than nothing and should help Linux distributions quite a lot. And there's no way to catch the latter issue anyway. Change-Id: I049a653beeb5454c9539ffff13e3fff36400ebbd Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- mkspecs/features/data/unix/findclasslist.pl | 59 +++++++++++++++++++++++++++++ mkspecs/features/qt_module.prf | 15 +++++++- 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 mkspecs/features/data/unix/findclasslist.pl diff --git a/mkspecs/features/data/unix/findclasslist.pl b/mkspecs/features/data/unix/findclasslist.pl new file mode 100644 index 0000000000..9113b4921c --- /dev/null +++ b/mkspecs/features/data/unix/findclasslist.pl @@ -0,0 +1,59 @@ +#!/usr/bin/env perl +############################################################################# +## +## Copyright (C) 2015 Intel Corporation +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the build configuration tools of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL21$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see http://www.qt.io/terms-conditions. For further +## information use the contact form at http://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 or version 3 as published by the Free +## Software Foundation and appearing in the file LICENSE.LGPLv21 and +## LICENSE.LGPLv3 included in the packaging of this file. Please review the +## following information to ensure the GNU Lesser General Public License +## requirements will be met: https://www.gnu.org/licenses/lgpl.html and +## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## As a special exception, The Qt Company gives you certain additional +## rights. These rights are described in The Qt Company LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## $QT_END_LICENSE$ +## +############################################################################# + +use strict; +my $syntax = "findclasslist.pl [private header list]\n" . + "Replaces \@CLASSLIST\@ with the classes found in the header files\n"; +$\ = $/; +while () { + chomp; + unless (/\@CLASSLIST\@/) { + print; + next; + } + + # Replace @CLASSLIST@ with the class list + for my $header (@ARGV) { + open HDR, "<$header" or die("Could not open header $header: $!"); + my $comment = " /* $header */"; + while (my $line = ) { + # Match a struct or class declaration, but not a forward declaration + $line =~ /^(?:struct|class) (?:Q_.*_EXPORT)? (\w+)(?!;)/ or next; + print $comment if $comment; + printf " *%d%s*;\n", length $1, $1; + $comment = 0; + } + close HDR; + } +} diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index b623d68767..10911fa6df 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -194,8 +194,11 @@ unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!no_linker_version_script:!static { internal_module { verscript_content = "Qt_$${QT_MAJOR_VERSION}_PRIVATE_API { *; };" } else { + verscript_content = "Qt_$${QT_MAJOR_VERSION}_PRIVATE_API {" \ + " qt_private_api_tag*;" "@CLASSLIST@" "};" + current = Qt_$$QT_MAJOR_VERSION - verscript_content = "$$current { *; };" + verscript_content += "$$current { *; };" isEmpty(QT_NAMESPACE): tag_symbol = qt_version_tag else: tag_symbol = qt_version_tag_$$QT_NAMESPACE @@ -205,6 +208,16 @@ unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!no_linker_version_script:!static { equals(i, $$QT_MINOR_VERSION): verscript_content += "$$current { $$tag_symbol; } $$previous;" else: verscript_content += "$$current {} $$previous;" } + + # Add a post-processing step to replace the @CLASSLIST@ + verscriptprocess.commands = perl $${PWD}/data/unix/findclasslist.pl < $^ > $@ + verscriptprocess.target = $$verscript + verscriptprocess.depends = $${verscript}.in + for(header, SYNCQT.PRIVATE_HEADER_FILES): \ + verscriptprocess.depends += $${_PRO_FILE_PWD_}/$$header + QMAKE_EXTRA_TARGETS += verscriptprocess + PRE_TARGETDEPS += $$verscript + verscript = $${verscript}.in } write_file($$verscript, verscript_content)|error("Aborting.") unset(current) -- cgit v1.2.3