diff --git a/clang/include/clang/Config/config.h.cmake b/clang/include/clang/Config/config.h.cmake --- a/clang/include/clang/Config/config.h.cmake +++ b/clang/include/clang/Config/config.h.cmake @@ -45,6 +45,9 @@ #cmakedefine CLANG_CONFIG_FILE_SYSTEM_DIR "${CLANG_CONFIG_FILE_SYSTEM_DIR}" #cmakedefine CLANG_CONFIG_FILE_USER_DIR "${CLANG_CONFIG_FILE_USER_DIR}" +/* Name of the env variable for the configuration file */ +#cmakedefine ENV_CONFIG_FILE_NAME "${ENV_CONFIG_FILE_NAME}" + /* Default to all compiler invocations for --sysroot=. */ #define DEFAULT_SYSROOT "${DEFAULT_SYSROOT}" diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -702,6 +702,12 @@ /// \returns true if error occurred. bool loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx); + /// Tries to load options from configuration file specified by environment + // variable. + // + // \returns true if error occurred. + bool readConfigFileFromEnv(); + /// Read options from the specified file. /// /// \param [in] FileName File to read. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1034,6 +1034,35 @@ return false; } +bool Driver::readConfigFileFromEnv() { + llvm::cl::ExpansionContext ExpCtx(Saver.getAllocator(), + llvm::cl::tokenizeConfigFile); + ExpCtx.setVFS(&getVFS()); + std::string EnvCfgName = "CONFIG_FILE"; + +#if defined(ENV_CONFIG_FILE_NAME) + EnvCfgName = ENV_CONFIG_FILE_NAME; +#endif + const char *EnvCfgFileName = getenv(EnvCfgName.c_str()); + + if (!EnvCfgFileName) + return false; + + std::string CfgFileName = EnvCfgFileName; + if (CfgFileName.empty()) { + Diag(diag::err_drv_cannot_read_config_file) << CfgFileName << ""; + return true; + } + + // If argument contains directory separator, treat it as a path to + // configuration file. + SmallString<128> CfgFilePath; + if (llvm::sys::path::is_relative(CfgFileName)) + llvm::sys::fs::current_path(CfgFilePath); + llvm::sys::path::append(CfgFilePath, CfgFileName); + return readConfigFile(CfgFilePath, ExpCtx); +} + bool Driver::loadConfigFiles() { llvm::cl::ExpansionContext ExpCtx(Saver.getAllocator(), llvm::cl::tokenizeConfigFile); @@ -1099,6 +1128,9 @@ } } + if (ConfigFiles.empty()) + return readConfigFileFromEnv(); + // No error occurred. return false; } diff --git a/clang/test/Driver/config-file-from-env.c b/clang/test/Driver/config-file-from-env.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/config-file-from-env.c @@ -0,0 +1,51 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: mkdir %t/empty_dir +// RUN: echo "-Wall" > %t/c.cfg +// RUN: echo "-ffast-math" > %t/cxx.cfg +// RUN: touch %t/unreadable.cfg +// RUN: chmod 000 %t/unreadable.cfg +// RUN: touch %t/test.c +// RUN: touch %t/test.cpp + +// RUN: env CONFIG_FILE=%t/c.cfg %clang -S %t/test.c -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-C1 +// CHECK-C1: Configuration file: {{.*}}/c.cfg +// CHECK-C1: -Wall + +// RUN: env CONFIG_FILE=%t/unreadable.cfg not %clang -S %t/test.c -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-C2 +// CHECK-C2: error: cannot read configuration file '{{.*}}/unreadable.cfg' + +// RUN: env CONFIG_FILE=%t/c.cfg %clang -S %t/test.c --config %S/Inputs/config-1.cfg -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-C3 +// CHECK-C3: Configuration file: {{.*}}/config-1.cfg +// CHECK-C3: -Werror +// CHECK-C3-NOT: -Wall + +// RUN: env CONFIG_FILE= not %clang -S %t/test.c -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-C4 +// CHECK-C4: error: cannot read configuration file '' + +// RUN: env CONFIG_FILE=%t/empty_dir not %clang -S %t/test.c -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-C5 +// CHECK-C5: error: configuration file '{{.*}}/empty_dir' cannot be opened: not a regular file + +// RUN: env CONFIG_FILE=%t/cxx.cfg %clang++ -S %t/test.cpp -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-CXX1 +// CHECK-CXX1: Configuration file: {{.*}}/cxx.cfg +// CHECK-CXX1: -ffast-math + +// RUN: env CONFIG_FILE=%t/unreadable.cfg not %clang++ -S %t/test.cpp -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-CXX2 +// CHECK-CXX2: error: cannot read configuration file '{{.*}}/unreadable.cfg' + +// RUN: env CONFIG_FILE=%t/cxx.cfg %clang++ -S %t/test.cpp --config %S/Inputs/config-1.cfg -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-CXX3 +// CHECK-CXX3: Configuration file: {{.*}}/config-1.cfg +// CHECK-CXX3: -Werror +// CHECK-CXX3-NOT: -ffast-math + +// RUN: env CONFIG_FILE= not %clang++ -S %t/test.cpp -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-CXX4 +// CHECK-CXX4: error: cannot read configuration file '' + +// RUN: env CONFIG_FILE=%t/empty_dir not %clang++ -S %t/test.cpp -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-CXX5 +// CHECK-CXX5: error: configuration file '{{.*}}/empty_dir' cannot be opened: not a regular file + +// RUN: env CONFIG_FILE=%t/c.cfg %clang++ --config=%t/cxx.cfg -S %t/test.cpp -o /dev/null -### 2>&1 | FileCheck %s -check-prefix CHECK-CXX6 +// CHECK-CXX6-NOT: Configuration file: {{.*}}/c.cfg +// CHECK-CXX6-NOT: -Wall + +// RUN: rm -rf %t