Add a QT_REQUIRE_CONFIG(feature) macro
This macro expands into a static_assert and can be used to trigger a compile error if a certain feature is not available when trying to compile some code. This is especially useful to protect against accidental inclusion of headers that implement functionality related to a feature. Change-Id: I456c55b989ce5f35f3af0e13c1886a85c23dfe29 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
31a63b6903
commit
8d6f2e7e15
@ -200,9 +200,11 @@ sub shouldMasterInclude {
|
|||||||
}
|
}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Syntax: classNames(iheader, clean)
|
# Syntax: classNames(iheader, clean, requires)
|
||||||
# Params: iheader, string, filename to parse for classname "symlinks"
|
# Params: iheader, string, filename to parse for classname "symlinks"
|
||||||
# (out) clean, boolean, will be set to false if the header isn't clean
|
# (out) clean, boolean, will be set to false if the header isn't clean
|
||||||
|
# (out) requires, string, will be set to non-empty if the header
|
||||||
|
# requires a feature
|
||||||
#
|
#
|
||||||
# Purpose: Scans through iheader to find all classnames that should be
|
# Purpose: Scans through iheader to find all classnames that should be
|
||||||
# synced into library's include structure.
|
# synced into library's include structure.
|
||||||
@ -210,8 +212,9 @@ sub shouldMasterInclude {
|
|||||||
######################################################################
|
######################################################################
|
||||||
sub classNames {
|
sub classNames {
|
||||||
my @ret;
|
my @ret;
|
||||||
my ($iheader, $clean) = @_;
|
my ($iheader, $clean, $requires) = @_;
|
||||||
$$clean = 1;
|
$$clean = 1;
|
||||||
|
$$requires = "";
|
||||||
|
|
||||||
my $ihdrbase = basename($iheader);
|
my $ihdrbase = basename($iheader);
|
||||||
my $classname = $classnames{$ihdrbase};
|
my $classname = $classnames{$ihdrbase};
|
||||||
@ -236,6 +239,7 @@ sub classNames {
|
|||||||
$line .= ";" if($line =~ m/^QT_(BEGIN|END)_NAMESPACE(_[A-Z]+)*[\r\n]*$/); #qt macro
|
$line .= ";" if($line =~ m/^QT_(BEGIN|END)_NAMESPACE(_[A-Z]+)*[\r\n]*$/); #qt macro
|
||||||
$line .= ";" if($line =~ m/^QT_MODULE\(.*\)[\r\n]*$/); # QT_MODULE macro
|
$line .= ";" if($line =~ m/^QT_MODULE\(.*\)[\r\n]*$/); # QT_MODULE macro
|
||||||
$line .= ";" if($line =~ m/^QT_WARNING_(PUSH|POP|DISABLE_\w+\(.*\))[\r\n]*$/); # qt macros
|
$line .= ";" if($line =~ m/^QT_WARNING_(PUSH|POP|DISABLE_\w+\(.*\))[\r\n]*$/); # qt macros
|
||||||
|
$$requires = $1 if ($line =~ m/^QT_REQUIRE_CONFIG\((.*)\);[\r\n]*$/);
|
||||||
$parsable .= " " . $line;
|
$parsable .= " " . $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -706,6 +710,21 @@ sub isQpaHeader
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub globosort($$) {
|
||||||
|
my ($a, $b) = @_;
|
||||||
|
if ($a =~ /^q(.*)global\.h$/) {
|
||||||
|
my $sa = $1;
|
||||||
|
if ($b =~ /^q(.*)global\.h$/) {
|
||||||
|
my $sb = $1;
|
||||||
|
# Compare stems so qglobal.h (empty stem) is first:
|
||||||
|
return $sa cmp $sb;
|
||||||
|
}
|
||||||
|
return -1; # $a is global, so before $b
|
||||||
|
}
|
||||||
|
return +1 if $b =~ /^q.*global\.h$/; # $a not global, so after $b
|
||||||
|
return $a cmp $b;
|
||||||
|
}
|
||||||
|
|
||||||
# check if this is an in-source build, and if so use that as the basedir too
|
# check if this is an in-source build, and if so use that as the basedir too
|
||||||
$basedir = locateSyncProfile($out_basedir);
|
$basedir = locateSyncProfile($out_basedir);
|
||||||
if ($basedir) {
|
if ($basedir) {
|
||||||
@ -914,10 +933,7 @@ foreach my $lib (@modules_to_sync) {
|
|||||||
my $pri_clean_files = "";
|
my $pri_clean_files = "";
|
||||||
|
|
||||||
my $libcapitals = uc($lib);
|
my $libcapitals = uc($lib);
|
||||||
my $master_contents =
|
my %master_contents = ();
|
||||||
"#ifndef QT_".$libcapitals."_MODULE_H\n" .
|
|
||||||
"#define QT_".$libcapitals."_MODULE_H\n" .
|
|
||||||
"#include <$lib/${lib}Depends>\n";
|
|
||||||
|
|
||||||
#remove the old files
|
#remove the old files
|
||||||
if($remove_stale) {
|
if($remove_stale) {
|
||||||
@ -1017,6 +1033,7 @@ foreach my $lib (@modules_to_sync) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $clean_header;
|
my $clean_header;
|
||||||
|
my $requires;
|
||||||
my $iheader = $subdir . "/" . $header;
|
my $iheader = $subdir . "/" . $header;
|
||||||
$iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow);
|
$iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow);
|
||||||
if ($check_includes) {
|
if ($check_includes) {
|
||||||
@ -1025,7 +1042,7 @@ foreach my $lib (@modules_to_sync) {
|
|||||||
&& $header =~ /_p\.h$/ && $subdir !~ /3rdparty/;
|
&& $header =~ /_p\.h$/ && $subdir !~ /3rdparty/;
|
||||||
check_header($lib, $header, $iheader, $public_header, $private_header);
|
check_header($lib, $header, $iheader, $public_header, $private_header);
|
||||||
}
|
}
|
||||||
my @classes = $public_header && (!$minimal && $is_qt) ? classNames($iheader, \$clean_header) : ();
|
my @classes = $public_header && (!$minimal && $is_qt) ? classNames($iheader, \$clean_header, \$requires) : ();
|
||||||
if($showonly) {
|
if($showonly) {
|
||||||
print "$header [$lib]\n";
|
print "$header [$lib]\n";
|
||||||
foreach(@classes) {
|
foreach(@classes) {
|
||||||
@ -1059,7 +1076,7 @@ foreach my $lib (@modules_to_sync) {
|
|||||||
my $injection = "";
|
my $injection = "";
|
||||||
if($public_header) {
|
if($public_header) {
|
||||||
#put it into the master file
|
#put it into the master file
|
||||||
$master_contents .= "#include \"$public_header\"\n" if (!$shadow && shouldMasterInclude($iheader));
|
$master_contents{$public_header} = $requires if (!$shadow && shouldMasterInclude($iheader));
|
||||||
|
|
||||||
#deal with the install directives
|
#deal with the install directives
|
||||||
foreach my $class (@classes) {
|
foreach my $class (@classes) {
|
||||||
@ -1074,7 +1091,7 @@ foreach my $lib (@modules_to_sync) {
|
|||||||
$injection .= ":$class";
|
$injection .= ":$class";
|
||||||
}
|
}
|
||||||
$pri_install_files.= "$pri_install_iheader ";;
|
$pri_install_files.= "$pri_install_iheader ";;
|
||||||
$pri_clean_files .= "$pri_install_iheader " if ($clean_header);
|
$pri_clean_files .= "$pri_install_iheader".($requires ? ":".$requires : "")." " if ($clean_header);
|
||||||
}
|
}
|
||||||
elsif ($qpa_header) {
|
elsif ($qpa_header) {
|
||||||
$pri_install_qpafiles.= "$pri_install_iheader ";;
|
$pri_install_qpafiles.= "$pri_install_iheader ";;
|
||||||
@ -1113,8 +1130,17 @@ foreach my $lib (@modules_to_sync) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# close the master include:
|
# populate the master include:
|
||||||
$master_contents .=
|
my $master_contents =
|
||||||
|
"#ifndef QT_".$libcapitals."_MODULE_H\n" .
|
||||||
|
"#define QT_".$libcapitals."_MODULE_H\n" .
|
||||||
|
"#include <$lib/${lib}Depends>\n" .
|
||||||
|
join("", map {
|
||||||
|
my $rq = $master_contents{$_};
|
||||||
|
($rq ? "#if QT_CONFIG($rq)\n" : "") .
|
||||||
|
"#include \"$_\"\n" .
|
||||||
|
($rq ? "#endif\n" : "")
|
||||||
|
} sort globosort keys %master_contents) .
|
||||||
"#include \"".lc($lib)."version.h\"\n" .
|
"#include \"".lc($lib)."version.h\"\n" .
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
|
||||||
|
@ -243,16 +243,23 @@ headersclean:!internal_module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
!isEmpty(hcleanCOMMAND):if(!qtConfig(debug_and_release)|CONFIG(release, debug|release)) {
|
!isEmpty(hcleanCOMMAND):if(!qtConfig(debug_and_release)|CONFIG(release, debug|release)) {
|
||||||
|
CLEAN_HEADERS =
|
||||||
|
for (h, SYNCQT.CLEAN_HEADER_FILES) {
|
||||||
|
hh = $$split(h, :)
|
||||||
|
hr = $$member(hh, 1)
|
||||||
|
isEmpty(hr)|qtConfig($$hr): \
|
||||||
|
CLEAN_HEADERS += $$member(hh, 0)
|
||||||
|
}
|
||||||
|
CLEAN_HEADERS -= $$HEADERSCLEAN_EXCLUDE
|
||||||
header_check.dependency_type = TYPE_C
|
header_check.dependency_type = TYPE_C
|
||||||
header_check.CONFIG += no_link
|
header_check.CONFIG += no_link
|
||||||
header_check.output = ${QMAKE_VAR_OBJECTS_DIR}header_${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
|
header_check.output = ${QMAKE_VAR_OBJECTS_DIR}header_${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
|
||||||
header_check.input = SYNCQT.CLEAN_HEADER_FILES
|
header_check.input = CLEAN_HEADERS
|
||||||
header_check.variable_out = PRE_TARGETDEPS
|
header_check.variable_out = PRE_TARGETDEPS
|
||||||
header_check.name = headercheck ${QMAKE_FILE_IN}
|
header_check.name = headercheck ${QMAKE_FILE_IN}
|
||||||
header_check.commands = $$hcleanCOMMAND
|
header_check.commands = $$hcleanCOMMAND
|
||||||
silent:header_check.commands = @echo compiling[header] ${QMAKE_FILE_IN} && $$hcleanCOMMAND
|
silent:header_check.commands = @echo compiling[header] ${QMAKE_FILE_IN} && $$hcleanCOMMAND
|
||||||
QMAKE_EXTRA_COMPILERS += header_check
|
QMAKE_EXTRA_COMPILERS += header_check
|
||||||
SYNCQT.CLEAN_HEADER_FILES -= $$HEADERSCLEAN_EXCLUDE
|
|
||||||
}
|
}
|
||||||
unset(hcleanCOMMAND)
|
unset(hcleanCOMMAND)
|
||||||
unset(hcleanFLAGS)
|
unset(hcleanFLAGS)
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
1: The feature is available
|
1: The feature is available
|
||||||
*/
|
*/
|
||||||
#define QT_CONFIG(feature) (1/QT_FEATURE_##feature == 1)
|
#define QT_CONFIG(feature) (1/QT_FEATURE_##feature == 1)
|
||||||
|
#define QT_REQUIRE_CONFIG(feature) Q_STATIC_ASSERT_X(QT_FEATURE_##feature == 1, "Required feature " #feature " for file " __FILE__ " not vailable.")
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
||||||
# define QT_NO_UNSHARABLE_CONTAINERS
|
# define QT_NO_UNSHARABLE_CONTAINERS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user