#!/usr/bin/env perl # Copyright (C) 2016 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only # Reads list of headers in a file tree, from stdin, one per line, as # paths relative to current working directory, in which sync.profile # must be present. Emits, to stdout, the same list of headers that # syncqt.pl would treat as public, if in the given file tree - in the # same format. # # Assumes the incoming file list has had some filtering applied to it; # see api-review-gen's function apiheaders (). To model a given git # checkout, you need to check out its sync.profile and use git ls-tree # -r --name-only to list its headers (via some filtering by grep); # pipe that into this script. # For such documentation as exists of sync.profile, see: # https://wiki.qt.io/Creating_a_new_module_or_tool_for_Qt#The_sync.profile_script use File::Basename 'basename'; ###################################################################### # Syntax: normalizePath(\$path) # Params: Reference to a path that's going to be normalized. # # Purpose: Converts the path into a form that can be used as include # path from C++ sources and qmake's .pro files. # No-op except on Windows. # Returns: -none- ###################################################################### my $onMSys = $^O eq "msys"; sub normalizePath ($) { my $s = shift; $$s =~ s=\\=/=g; # Fix up drive letters on MSys: if ($onMSys && ($$s =~ m,^/([a-zA-Z])/(.*), || $$s =~ m,^([a-zA-Z]):/(.*),)) { $$s = lc($1) . ":/$2"; } } sub cannot ($) { my $msg = shift; my $me = basename($0); die "$me couldn't $msg"; } # Apt to be set by the module's sync.profile: our (%modules, %moduleheaders, @allmoduleheadersprivate); our @qpa_headers = (); # regexes matching Qt Platform Abstraction headers our @ignore_headers = (); our %inject_headers = (); # TODO: add a variable by which modules can tell us where to find QML API # Load the module's sync.profile: my ($base, $sync) = ('.', 'sync.profile'); if (! -f $sync && -f "Source/$sync" ) { $base = 'Source'; $sync = "$base/$sync"; } if (-f $sync) { our (%classnames, %deprecatedheaders); our $basedir = $base; # Used by sync.profile unless (my $result = do "./$sync") { &cannot("parse $sync: $@") if $@; &cannot("execute $sync: $!") unless defined $result; } } else { &cannot("find $sync"); } # Short-cut for testing if entry is in list (our only use of these lists): my %allmoduleheadersprivate = map { $_ => 1 } @allmoduleheadersprivate; my %qpa_headers = map { $_ => 1 } @qpa_headers; my %ignore_headers = map { $_ => 1 } @ignore_headers; foreach my $dir (keys %inject_headers) { foreach $header ($inject_headers{$dir}) { $ignore_headers{"$dir/$header"} = 1; } } # Gather file-names listed (one per line) on STDIN, filtering out cruft: my @allheaders = (); while () { chomp; normalizePath(\$_); next if $ignore_headers{basename($_)} || $qpa_headers{$_}; push @allheaders, $_ if $_; } foreach my $lib (keys %modules) { next if $allmoduleheadersprivate{$lib}; # iteration info my $pathtoheaders = $moduleheaders{$lib} ? $moduleheaders{$lib} : ""; my $module = $modules{$lib}; my $is_qt = $module !~ s/^!//; my @dirs = split(/;/, $module); shift @dirs if $dirs[0] =~ s/^>//; foreach my $module_dir (@dirs) { next if $module_dir =~ /^\^/; my @headers_paths = split(/;/, $pathtoheaders); if (@headers_paths) { @headers_paths = map { "$module_dir/$_" } @headers_paths; } else { push @headers_paths, $module_dir; } foreach my $header_dir (@headers_paths) { $header_dir =~ s!/*$!/!; $header_dir =~ s!^\./+!!; # Strip $basedir prefix my @selected = grep /^\Q$header_dir\E/, @allheaders; print join("\n", @selected) . "\n" if @selected; } } } exit 0;