[Modules] Add platform and environment features to requires clause

Allows module map writers to add build requirements based on
platform/os. This helps when target features and language dialects
aren't enough to conditionalize building a module, among other things,
it allow module maps for different platforms to live in the same file.

rdar://problem/43909745

Differential Revision: https://reviews.llvm.org/D51910

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@342499 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bruno Cardoso Lopes 2018-09-18 17:11:13 +00:00
parent 16f27fb3e9
commit bd5ee58406
3 changed files with 118 additions and 2 deletions

View File

@ -411,7 +411,7 @@ A *requires-declaration* specifies the requirements that an importing translatio
*feature*:
``!``:sub:`opt` *identifier*
The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module. When building a module for use by a compilation, submodules requiring unavailable features are ignored. The optional ``!`` indicates that a feature is incompatible with the module.
The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects, platforms, environments and target specific features. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module. When building a module for use by a compilation, submodules requiring unavailable features are ignored. The optional ``!`` indicates that a feature is incompatible with the module.
The following features are defined:
@ -466,6 +466,11 @@ tls
*target feature*
A specific target feature (e.g., ``sse4``, ``avx``, ``neon``) is available.
*platform/os*
A os/platform variant (e.g. ``freebsd``, ``win32``, ``windows``, ``linux``, ``ios``, ``macos``, ``iossimulator``) is available.
*environment*
A environment variant (e.g. ``gnu``, ``gnueabi``, ``android``, ``msvc``) is available.
**Example:** The ``std`` module can be extended to also include C++ and C++11 headers using a *requires-declaration*:

View File

@ -71,6 +71,37 @@ Module::~Module() {
}
}
static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) {
StringRef Platform = Target.getPlatformName();
StringRef Env = Target.getTriple().getEnvironmentName();
// Attempt to match platform and environment.
if (Platform == Feature || Target.getTriple().getOSName() == Feature ||
Env == Feature)
return true;
auto CmpPlatformEnv = [](StringRef LHS, StringRef RHS) {
auto Pos = LHS.find("-");
if (Pos == StringRef::npos)
return false;
SmallString<128> NewLHS = LHS.slice(0, Pos);
NewLHS += LHS.slice(Pos+1, LHS.size());
return NewLHS == RHS;
};
SmallString<128> PlatformEnv = Target.getTriple().getOSAndEnvironmentName();
// Darwin has different but equivalent variants for simulators, example:
// 1. x86_64-apple-ios-simulator
// 2. x86_64-apple-iossimulator
// where both are valid examples of the same platform+environment but in the
// variant (2) the simulator is hardcoded as part of the platform name. Both
// forms above should match for "iossimulator" requirement.
if (Target.getTriple().isOSDarwin() && PlatformEnv.endswith("simulator"))
return PlatformEnv == Feature || CmpPlatformEnv(PlatformEnv, Feature);
return PlatformEnv == Feature;
}
/// Determine whether a translation unit built using the current
/// language options has the given feature.
static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
@ -93,7 +124,8 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
.Case("opencl", LangOpts.OpenCL)
.Case("tls", Target.isTLSSupported())
.Case("zvector", LangOpts.ZVector)
.Default(Target.hasFeature(Feature));
.Default(Target.hasFeature(Feature) ||
isPlatformEnvironment(Target, Feature));
if (!HasFeature)
HasFeature = std::find(LangOpts.ModuleFeatures.begin(),
LangOpts.ModuleFeatures.end(),

View File

@ -0,0 +1,79 @@
// Clear and create directories
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: mkdir %t/cache
// RUN: mkdir %t/InputsA
// RUN: echo "module RequiresMacOS {" >> %t/InputsA/module.map
// RUN: echo " requires macos" >> %t/InputsA/module.map
// RUN: echo "}" >> %t/InputsA/module.map
// RUN: echo "module RequiresNotiOS {" >> %t/InputsA/module.map
// RUN: echo " requires !ios" >> %t/InputsA/module.map
// RUN: echo "}" >> %t/InputsA/module.map
// RUN: echo "module RequiresMain {" >> %t/InputsA/module.map
// RUN: echo " module SubRequiresNotiOS {" >> %t/InputsA/module.map
// RUN: echo " requires !ios" >> %t/InputsA/module.map
// RUN: echo " }" >> %t/InputsA/module.map
// RUN: echo "}" >> %t/InputsA/module.map
// RUN: %clang_cc1 -triple=x86_64-apple-macosx10.6 -DENABLE_DARWIN -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x objective-c -I%t/InputsA -verify %s
// expected-no-diagnostics
// RUN: not %clang_cc1 -triple=arm64-apple-ios -DENABLE_DARWIN -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x objective-c -I%t/InputsA %s 2> %t/notios
// RUN: FileCheck %s -check-prefix=CHECK-IOS < %t/notios
#ifdef ENABLE_DARWIN
// CHECK-IOS: module 'RequiresMacOS' requires feature 'macos'
@import RequiresMacOS;
// CHECK-IOS: module 'RequiresNotiOS' is incompatible with feature 'ios'
@import RequiresNotiOS;
// We should never get errors for submodules that don't match
// CHECK-IOS-NOT: module 'RequiresMain'
@import RequiresMain;
#endif
// RUN: mkdir %t/InputsB
// RUN: echo "module RequiresiOSSim {" >> %t/InputsB/module.map
// RUN: echo " requires iossimulator" >> %t/InputsB/module.map
// RUN: echo "}" >> %t/InputsB/module.map
// RUN: %clang_cc1 -triple=x86_64-apple-iossimulator -DENABLE_IOSSIM -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x objective-c -I%t/InputsB %s -verify
// RUN: %clang_cc1 -triple=x86_64-apple-ios-simulator -DENABLE_IOSSIM -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x objective-c -I%t/InputsB %s -verify
#ifdef ENABLE_IOSSIM
@import RequiresiOSSim;
#endif
// RUN: mkdir %t/InputsC
// RUN: echo "module RequiresLinuxEABIA {" >> %t/InputsC/module.map
// RUN: echo " requires linux, gnueabi" >> %t/InputsC/module.map
// RUN: echo "}" >> %t/InputsC/module.map
// RUN: echo "module RequiresLinuxEABIB {" >> %t/InputsC/module.map
// RUN: echo " requires gnueabi" >> %t/InputsC/module.map
// RUN: echo "}" >> %t/InputsC/module.map
// RUN: echo "module RequiresLinuxEABIC {" >> %t/InputsC/module.map
// RUN: echo " requires linux" >> %t/InputsC/module.map
// RUN: echo "}" >> %t/InputsC/module.map
// RUN: %clang_cc1 -triple=armv8r-none-linux-gnueabi -DENABLE_LINUXEABI -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x objective-c -I%t/InputsC %s -verify
#ifdef ENABLE_LINUXEABI
@import RequiresLinuxEABIA;
@import RequiresLinuxEABIB;
@import RequiresLinuxEABIC;
#endif
// RUN: mkdir %t/InputsD
// RUN: echo "module RequiresWinMSVCA {" >> %t/InputsD/module.map
// RUN: echo " requires windows" >> %t/InputsD/module.map
// RUN: echo "}" >> %t/InputsD/module.map
// RUN: echo "module RequiresWinMSVCB {" >> %t/InputsD/module.map
// RUN: echo " requires windows, msvc" >> %t/InputsD/module.map
// RUN: echo "}" >> %t/InputsD/module.map
// RUN: echo "module RequiresWinMSVCC {" >> %t/InputsD/module.map
// RUN: echo " requires msvc" >> %t/InputsD/module.map
// RUN: echo "}" >> %t/InputsD/module.map
// RUN: %clang_cc1 -triple=thumbv7-unknown-windows-msvc -DENABLE_WINMSVC -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x objective-c -I%t/InputsD %s -verify
#ifdef ENABLE_WINMSVC
@import RequiresWinMSVCA;
@import RequiresWinMSVCB;
@import RequiresWinMSVCC;
#endif