Sort out target environments used in different components.

SPIRV-Tools has its own target environment definition, and public
shaderc API has its own. A new one is added into Compiler in
shaderc_util, for better isolation.

Now shaderc_util::Compiler's interface accepts target environment,
not glslang messages anymore. All the conversion to glslang messages
are done in the implementation now.
diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc
index f301158..4702608 100644
--- a/libshaderc/src/shaderc.cc
+++ b/libshaderc/src/shaderc.cc
@@ -70,20 +70,6 @@
   return EShLangCount;
 }
 
-// Converts shaderc_target_env to EShMessages
-EShMessages GetMessageRules(shaderc_target_env target) {
-  switch (target) {
-    case shaderc_target_env_opengl_compat:
-      break;
-    case shaderc_target_env_opengl:
-      return static_cast<EShMessages>(EShMsgSpvRules | EShMsgCascadingErrors);
-    case shaderc_target_env_vulkan:
-      return static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules |
-                                      EShMsgCascadingErrors);
-  }
-  return EShMsgCascadingErrors;
-}
-
 // A wrapper functor class to be used as stage deducer for libshaderc_util
 // Compile() interface. When the given shader kind is one of the default shader
 // kinds, this functor will be called if #pragma is not found in the source
@@ -237,14 +223,29 @@
   void* user_data_;
 };
 
+// Converts the target env to the corresponding one in shaderc_util::Compiler.
+shaderc_util::Compiler::TargetEnv GetCompilerTargetEnv(shaderc_target_env env) {
+  switch (env) {
+    case shaderc_target_env_opengl:
+      return shaderc_util::Compiler::TargetEnv::OpenGL;
+    case shaderc_target_env_opengl_compat:
+      return shaderc_util::Compiler::TargetEnv::OpenGLCompat;
+    case shaderc_target_env_vulkan:
+    default:
+      break;
+  }
+
+  return shaderc_util::Compiler::TargetEnv::Vulkan;
+}
+
 }  // anonymous namespace
 
 struct shaderc_compile_options {
-  shaderc_compile_options() : include_user_data(nullptr) {}
+  shaderc_target_env target_env = shaderc_target_env_default;
   shaderc_util::Compiler compiler;
-  shaderc_include_resolve_fn include_resolver;
-  shaderc_include_result_release_fn include_result_releaser;
-  void* include_user_data;
+  shaderc_include_resolve_fn include_resolver = nullptr;
+  shaderc_include_result_release_fn include_result_releaser = nullptr;
+  void* include_user_data = nullptr;
 };
 
 shaderc_compile_options_t shaderc_compile_options_initialize() {
@@ -327,7 +328,8 @@
                                             uint32_t version) {
   // "version" reserved for future use, intended to distinguish between
   // different versions of a target environment
-  options->compiler.SetMessageRules(GetMessageRules(target));
+  options->target_env = target;
+  options->compiler.SetTargetEnv(GetCompilerTargetEnv(target));
 }
 
 void shaderc_compile_options_set_warnings_as_errors(
@@ -459,7 +461,7 @@
 shaderc_compilation_result_t shaderc_assemble_into_spv(
     const shaderc_compiler_t compiler, const char* source_assembly,
     size_t source_assembly_size,
-    const shaderc_compile_options_t /* additional_options */) {
+    const shaderc_compile_options_t additional_options) {
   auto* result = new (std::nothrow) shaderc_compilation_result_spv_binary;
   if (!result) return nullptr;
   result->compilation_status = shaderc_compilation_status_invalid_assembly;
@@ -469,7 +471,10 @@
   TRY_IF_EXCEPTIONS_ENABLED {
     spv_binary assembling_output_data = nullptr;
     std::string errors;
+    const auto target_env = additional_options ? additional_options->target_env
+                                               : shaderc_target_env_default;
     const bool assembling_succeeded = shaderc_util::SpirvToolsAssemble(
+        GetCompilerTargetEnv(target_env),
         {source_assembly, source_assembly + source_assembly_size},
         &assembling_output_data, &errors);
     result->num_errors = !assembling_succeeded;
diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc
index 88ed03d..521f109 100644
--- a/libshaderc/src/shaderc_cpp_test.cc
+++ b/libshaderc/src/shaderc_cpp_test.cc
@@ -130,15 +130,17 @@
   }
 
   // Assembles the given SPIR-V assembly and returns true on success.
-  bool AssemblingSuccess(const std::string& shader) const {
-    return compiler_.AssembleToSpv(shader).GetCompilationStatus() ==
+  bool AssemblingSuccess(const std::string& shader,
+                         const CompileOptions& options) const {
+    return compiler_.AssembleToSpv(shader, options).GetCompilationStatus() ==
            shaderc_compilation_status_success;
   }
 
   // Assembles the given SPIR-V assembly and returns true if the result contains
   // a valid SPIR-V module.
-  bool AssemblingValid(const std::string& shader) const {
-    return IsValidSpv(compiler_.AssembleToSpv(shader));
+  bool AssemblingValid(const std::string& shader,
+                       const CompileOptions& options) const {
+    return IsValidSpv(compiler_.AssembleToSpv(shader, options));
   }
 
   // Compiles a shader, expects compilation success, and returns the output
@@ -218,7 +220,7 @@
 }
 
 TEST_F(CppInterface, AssembleEmptyString) {
-  EXPECT_TRUE(AssemblingSuccess(""));
+  EXPECT_TRUE(AssemblingSuccess("", options_));
 }
 
 TEST_F(CppInterface, ResultObjectMoves) {
@@ -236,12 +238,20 @@
 }
 
 TEST_F(CppInterface, AssembleGarbageString) {
-  const auto result = compiler_.AssembleToSpv("jfalkds");
+  const auto result = compiler_.AssembleToSpv("jfalkds", options_);
   EXPECT_FALSE(CompilationResultIsSuccess(result));
   EXPECT_EQ(0u, result.GetNumWarnings());
   EXPECT_EQ(1u, result.GetNumErrors());
 }
 
+// TODO(antiagainst): right now there is no assembling difference for all the
+// target environments exposed by shaderc. So the following is just testing the
+// target environment is accepted.
+TEST_F(CppInterface, AssembleTargetEnv) {
+  options_.SetTargetEnvironment(shaderc_target_env_opengl, 0);
+  EXPECT_TRUE(AssemblingValid("OpCapability Shader", options_));
+}
+
 TEST_F(CppInterface, MinimalShader) {
   EXPECT_TRUE(CompilesToValidSpv(compiler_, kMinimalShader,
                                  shaderc_glsl_vertex_shader));
@@ -250,7 +260,7 @@
 }
 
 TEST_F(CppInterface, AssembleMinimalShader) {
-  EXPECT_TRUE(AssemblingValid(kMinimalShaderAssembly));
+  EXPECT_TRUE(AssemblingValid(kMinimalShaderAssembly, options_));
 }
 
 TEST_F(CppInterface, BasicOptions) {
diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc
index 6de7053..c14b9c3 100644
--- a/libshaderc/src/shaderc_test.cc
+++ b/libshaderc/src/shaderc_test.cc
@@ -266,11 +266,16 @@
 // checking methods. Subclass tests can access the compiler object to set their
 // properties.
 class AssembleStringTest : public testing::Test {
+ public:
+  AssembleStringTest() : options_(shaderc_compile_options_initialize()) {}
+  ~AssembleStringTest() { shaderc_compile_options_release(options_); }
+
  protected:
   // Assembles the given assembly and returns true on success.
   bool AssemblingSuccess(const std::string& assembly) {
     return CompilationResultIsSuccess(
-        Assembling(compiler_.get_compiler_handle(), assembly).result());
+        Assembling(compiler_.get_compiler_handle(), assembly, options_)
+            .result());
   }
 
   bool AssemblingValid(const std::string& assembly) {
@@ -280,6 +285,7 @@
   }
 
   Compiler compiler_;
+  shaderc_compile_options_t options_;
 };
 
 // Name holders so that we have test cases being grouped with only one real
@@ -312,6 +318,16 @@
   EXPECT_EQ(0u, shaderc_result_get_num_warnings(assembling.result()));
 }
 
+// TODO(antiagainst): right now there is no assembling difference for all the
+// target environments exposed by shaderc. So the following is just testing the
+// target environment is accepted.
+TEST_F(AssembleStringTest, AcceptTargetEnv) {
+  ASSERT_NE(nullptr, compiler_.get_compiler_handle());
+  shaderc_compile_options_set_target_env(options_, shaderc_target_env_opengl,
+                                         /* version = */ 0);
+  EXPECT_TRUE(AssemblingSuccess("OpCapability Shader"));
+}
+
 TEST_F(CompileStringTest, ReallyLongShader) {
   ASSERT_NE(nullptr, compiler_.get_compiler_handle());
   std::string minimal_shader = "";
diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h
index 8647a93..5b06ce1 100644
--- a/libshaderc_util/include/libshaderc_util/compiler.h
+++ b/libshaderc_util/include/libshaderc_util/compiler.h
@@ -22,7 +22,6 @@
 #include <utility>
 
 #include "glslang/Public/ShaderLang.h"
-#include "libshaderc_util/spirv_tools_wrapper.h"
 
 #include "counting_includer.h"
 #include "file_finder.h"
@@ -31,6 +30,10 @@
 
 namespace shaderc_util {
 
+// To break recursive including. This header is already included in
+// spirv_tools_wrapper.h, so cannot include spirv_tools_wrapper.h here.
+enum class PassId;
+
 // Initializes glslang on creation, and destroys it on completion.
 // This object is expected to be a singleton, so that internal
 // glslang state can be correctly handled.
@@ -89,6 +92,13 @@
 // Holds all of the state required to compile source GLSL into SPIR-V.
 class Compiler {
  public:
+  // Target environment.
+  enum class TargetEnv {
+    Vulkan,
+    OpenGL,
+    OpenGLCompat,
+  };
+
   enum class OutputType {
     SpirvBinary,  // A binary module, as defined by the SPIR-V specification.
     SpirvAssemblyText,  // Assembly syntax defined by the SPIRV-Tools project.
@@ -111,7 +121,7 @@
         suppress_warnings_(false),
         generate_debug_info_(false),
         enabled_opt_passes_(),
-        message_rules_(GetDefaultRules()) {}
+        target_env_(TargetEnv::Vulkan) {}
 
   // Requests that the compiler place debug information into the object code,
   // such as identifier names and line numbers.
@@ -134,11 +144,8 @@
   void AddMacroDefinition(const char* macro, size_t macro_length,
                           const char* definition, size_t definition_length);
 
-  // Sets message rules to be used when generating compiler warnings/errors
-  void SetMessageRules(EShMessages rules);
-
-  // Gets the message rules when generating compiler warnings/error.
-  EShMessages GetMessageRules() const;
+  // Sets the target environment.
+  void SetTargetEnv(TargetEnv env);
 
   // Forces (without any verification) the default version and profile for
   // subsequent CompileShader() calls.
@@ -174,11 +181,11 @@
   // binary code, the size is the number of bytes of valid data in the vector.
   // If the output is a text string, the size equals the length of that string.
   std::tuple<bool, std::vector<uint32_t>, size_t> Compile(
-      const shaderc_util::string_piece& input_source_string,
-      EShLanguage forced_shader_stage, const std::string& error_tag,
-      const std::function<EShLanguage(
-          std::ostream* error_stream,
-          const shaderc_util::string_piece& error_tag)>& stage_callback,
+      const string_piece& input_source_string, EShLanguage forced_shader_stage,
+      const std::string& error_tag,
+      const std::function<EShLanguage(std::ostream* error_stream,
+                                      const string_piece& error_tag)>&
+          stage_callback,
       CountingIncluder& includer, OutputType output_type,
       std::ostream* error_stream, size_t* total_warnings, size_t* total_errors,
       GlslInitializer* initializer) const;
@@ -206,10 +213,8 @@
   // to be default_version_/default_profile_ regardless of the #version
   // directive in the source code.
   std::tuple<bool, std::string, std::string> PreprocessShader(
-      const std::string& error_tag,
-      const shaderc_util::string_piece& shader_source,
-      const shaderc_util::string_piece& shader_preamble,
-      CountingIncluder& includer) const;
+      const std::string& error_tag, const string_piece& shader_source,
+      const string_piece& shader_preamble, CountingIncluder& includer) const;
 
   // Cleans up the preamble in a given preprocessed shader.
   //
@@ -225,11 +230,11 @@
   // delete the #extension directive we injected via preamble. Otherwise, we
   // need to adjust it if there exists a #version directive in the original
   // shader source code.
-  std::string CleanupPreamble(
-      const shaderc_util::string_piece& preprocessed_shader,
-      const shaderc_util::string_piece& error_tag,
-      const shaderc_util::string_piece& pound_extension,
-      int num_include_directives, bool is_for_next_line) const;
+  std::string CleanupPreamble(const string_piece& preprocessed_shader,
+                              const string_piece& error_tag,
+                              const string_piece& pound_extension,
+                              int num_include_directives,
+                              bool is_for_next_line) const;
 
   // Determines version and profile from command line, or the source code.
   // Returns the decoded version and profile pair on success. Otherwise,
@@ -243,8 +248,7 @@
   // EShLangCount.  If errors occur, the second element in the pair is the
   // error message.  Otherwise, it's an empty string.
   std::pair<EShLanguage, std::string> GetShaderStageFromSourceCode(
-      shaderc_util::string_piece filename,
-      const std::string& preprocessed_shader) const;
+      string_piece filename, const std::string& preprocessed_shader) const;
 
   // Determines version and profile from command line, or the source code.
   // Returns the decoded version and profile pair on success. Otherwise,
@@ -280,10 +284,12 @@
   // Optimization passes to be applied.
   std::vector<PassId> enabled_opt_passes_;
 
-  // Sets the glslang EshMessages bitmask for determining which dialect of GLSL
-  // and which SPIR-V codegen semantics are used. This impacts the warning &
-  // error messages as well as the set of available builtins
-  EShMessages message_rules_;
+  // The target environment to compile with. This controls the glslang
+  // EshMessages bitmask, which determines which dialect of GLSL and which
+  // SPIR-V codegen semantics are used. This impacts the warning & error
+  // messages as well as the set of available builtins, as per the
+  // implementation of glslang.
+  TargetEnv target_env_;
 };
 
 // Converts a string to a vector of uint32_t by copying the content of a given
diff --git a/libshaderc_util/include/libshaderc_util/spirv_tools_wrapper.h b/libshaderc_util/include/libshaderc_util/spirv_tools_wrapper.h
index 14a597d..b02e15d 100644
--- a/libshaderc_util/include/libshaderc_util/spirv_tools_wrapper.h
+++ b/libshaderc_util/include/libshaderc_util/spirv_tools_wrapper.h
@@ -18,21 +18,23 @@
 #include <string>
 #include <vector>
 
-#include "libshaderc_util/string_piece.h"
-
 #include "spirv-tools/libspirv.hpp"
 
+#include "libshaderc_util/compiler.h"
+#include "libshaderc_util/string_piece.h"
+
 namespace shaderc_util {
 // Assembles the given assembly. On success, returns true, writes the assembled
 // binary to *binary, and clears *errors. Otherwise, writes the error message
 // into *errors.
-bool SpirvToolsAssemble(const string_piece assembly, spv_binary* binary,
-                        std::string* errors);
+bool SpirvToolsAssemble(Compiler::TargetEnv env, const string_piece assembly,
+                        spv_binary* binary, std::string* errors);
 
 // Disassembles the given binary. Returns true and writes the disassembled text
 // to *text_or_error if successful. Otherwise, writes the error message to
 // *text_or_error.
-bool SpirvToolsDisassemble(const std::vector<uint32_t>& binary,
+bool SpirvToolsDisassemble(Compiler::TargetEnv env,
+                           const std::vector<uint32_t>& binary,
                            std::string* text_or_error);
 
 // The ids of a list of supported optimization passes.
@@ -46,7 +48,8 @@
 // in enabled_passes, without de-duplication. Returns true and writes the
 // optimized binary back to *binary if successful. Otherwise, writes errors to
 // *errors and the content of binary may be in an invalid state.
-bool SpirvToolsOptimize(const std::vector<PassId>& enabled_passes,
+bool SpirvToolsOptimize(Compiler::TargetEnv env,
+                        const std::vector<PassId>& enabled_passes,
                         std::vector<uint32_t>* binary, std::string* errors);
 
 }  // namespace shaderc_util
diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc
index fd6f65a..686f78f 100644
--- a/libshaderc_util/src/compiler.cc
+++ b/libshaderc_util/src/compiler.cc
@@ -22,6 +22,7 @@
 #include "libshaderc_util/message.h"
 #include "libshaderc_util/resources.h"
 #include "libshaderc_util/shader_stage.h"
+#include "libshaderc_util/spirv_tools_wrapper.h"
 #include "libshaderc_util/string_piece.h"
 #include "libshaderc_util/version_profile.h"
 
@@ -63,6 +64,22 @@
   directive = directive.strip("\" \n");
   return std::make_pair(line, directive);
 }
+
+// Gets the corresponding message rules for the given target environment.
+EShMessages GetMessageRules(shaderc_util::Compiler::TargetEnv env) {
+  using shaderc_util::Compiler;
+  switch (env) {
+    case Compiler::TargetEnv::OpenGLCompat:
+      break;
+    case Compiler::TargetEnv::OpenGL:
+      return static_cast<EShMessages>(EShMsgSpvRules | EShMsgCascadingErrors);
+    case Compiler::TargetEnv::Vulkan:
+      return static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules |
+                                      EShMsgCascadingErrors);
+  }
+  return EShMsgCascadingErrors;
+}
+
 }  // anonymous namespace
 
 namespace shaderc_util {
@@ -157,10 +174,10 @@
   shader.setPreamble(preamble.c_str());
 
   // TODO(dneto): Generate source-level debug info if requested.
-  bool success =
-      shader.parse(&shaderc_util::kDefaultTBuiltInResource, default_version_,
-                   default_profile_, force_version_profile_,
-                   kNotForwardCompatible, message_rules_, includer);
+  bool success = shader.parse(&shaderc_util::kDefaultTBuiltInResource,
+                              default_version_, default_profile_,
+                              force_version_profile_, kNotForwardCompatible,
+                              GetMessageRules(target_env_), includer);
 
   success &= PrintFilteredErrors(error_tag, error_stream, warnings_as_errors_,
                                  suppress_warnings_, shader.getInfoLog(),
@@ -183,7 +200,8 @@
 
   if (!enabled_opt_passes_.empty()) {
     std::string opt_errors;
-    if (!SpirvToolsOptimize(enabled_opt_passes_, &spirv, &opt_errors)) {
+    if (!SpirvToolsOptimize(target_env_, enabled_opt_passes_, &spirv,
+                            &opt_errors)) {
       *error_stream << "shaderc: internal error: compilation succeeded but "
                        "failed to optimize: "
                     << opt_errors << "\n";
@@ -193,7 +211,7 @@
 
   if (output_type == OutputType::SpirvAssemblyText) {
     std::string text_or_error;
-    if (!SpirvToolsDisassemble(spirv, &text_or_error)) {
+    if (!SpirvToolsDisassemble(target_env_, spirv, &text_or_error)) {
       *error_stream << "shaderc: internal error: compilation succeeded but "
                        "failed to disassemble: "
                     << text_or_error << "\n";
@@ -218,9 +236,7 @@
       definition ? std::string(definition, definition_length) : "";
 }
 
-void Compiler::SetMessageRules(EShMessages rules) { message_rules_ = rules; }
-
-EShMessages Compiler::GetMessageRules() const { return message_rules_; }
+void Compiler::SetTargetEnv(Compiler::TargetEnv env) { target_env_ = env; }
 
 void Compiler::SetForcedVersionProfile(int version, EProfile profile) {
   default_version_ = version;
@@ -272,8 +288,8 @@
   // The preprocessor might be sensitive to the target environment.
   // So combine the existing rules with the just-give-me-preprocessor-output
   // flag.
-  const auto rules =
-      static_cast<EShMessages>(EShMsgOnlyPreprocessor | message_rules_);
+  const auto rules = static_cast<EShMessages>(EShMsgOnlyPreprocessor |
+                                              GetMessageRules(target_env_));
 
   std::string preprocessed_shader;
   const bool success = shader.preprocess(
diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc
index 30d00de..b11e04b 100644
--- a/libshaderc_util/src/compiler_test.cc
+++ b/libshaderc_util/src/compiler_test.cc
@@ -25,13 +25,6 @@
 
 using shaderc_util::Compiler;
 
-// These are the flag combinations Glslang uses to set language
-// rules based on the target environment.
-const EShMessages kOpenGLCompatibilityRules = EShMsgDefault;
-const EShMessages kOpenGLRules = EShMsgSpvRules;
-const EShMessages kVulkanRules =
-    static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
-
 // A trivial vertex shader
 const char kVertexShader[] =
     "#version 140\n"
@@ -90,8 +83,7 @@
  private:
   // Returns a pair of empty strings.
   virtual glslang::TShader::Includer::IncludeResult* include_delegate(
-      const char*, glslang::TShader::Includer::IncludeType,
-      const char*,
+      const char*, glslang::TShader::Includer::IncludeType, const char*,
       size_t) override {
     return nullptr;
   }
@@ -132,6 +124,7 @@
     return SimpleCompilationSucceedsForOutputType(
         source, stage, Compiler::OutputType::SpirvBinary);
   }
+
  protected:
   Compiler compiler_;
   // The error string from the most recent compilation.
@@ -163,12 +156,12 @@
 TEST_F(CompilerTest, RespectTargetEnvOnOpenGLCompatibilityShader) {
   const EShLanguage stage = EShLangFragment;
 
-  compiler_.SetMessageRules(kOpenGLCompatibilityRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);
   EXPECT_TRUE(SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader, stage));
-  compiler_.SetMessageRules(kOpenGLRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);
   EXPECT_FALSE(
       SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader, stage));
-  compiler_.SetMessageRules(kVulkanRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);
   EXPECT_FALSE(
       SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader, stage));
   // Default compiler.
@@ -181,15 +174,15 @@
        RespectTargetEnvOnOpenGLCompatibilityShaderWhenDeducingStage) {
   const EShLanguage stage = EShLangCount;
 
-  compiler_.SetMessageRules(kOpenGLCompatibilityRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);
   EXPECT_TRUE(SimpleCompilationSucceeds(
       kOpenGLCompatibilityFragShaderDeducibleStage, stage))
       << errors_;
-  compiler_.SetMessageRules(kOpenGLRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);
   EXPECT_FALSE(SimpleCompilationSucceeds(
       kOpenGLCompatibilityFragShaderDeducibleStage, stage))
       << errors_;
-  compiler_.SetMessageRules(kVulkanRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);
   EXPECT_FALSE(SimpleCompilationSucceeds(
       kOpenGLCompatibilityFragShaderDeducibleStage, stage))
       << errors_;
@@ -203,37 +196,37 @@
 TEST_F(CompilerTest, RespectTargetEnvOnOpenGLShader) {
   const EShLanguage stage = EShLangVertex;
 
-  compiler_.SetMessageRules(kOpenGLCompatibilityRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);
   EXPECT_TRUE(SimpleCompilationSucceeds(kOpenGLVertexShader, stage));
 
-  compiler_.SetMessageRules(kOpenGLRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);
   EXPECT_TRUE(SimpleCompilationSucceeds(kOpenGLVertexShader, stage));
 }
 
 TEST_F(CompilerTest, RespectTargetEnvOnOpenGLShaderWhenDeducingStage) {
   const EShLanguage stage = EShLangCount;
 
-  compiler_.SetMessageRules(kOpenGLCompatibilityRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);
   EXPECT_TRUE(
       SimpleCompilationSucceeds(kOpenGLVertexShaderDeducibleStage, stage));
 
-  compiler_.SetMessageRules(kOpenGLRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);
   EXPECT_TRUE(
       SimpleCompilationSucceeds(kOpenGLVertexShaderDeducibleStage, stage));
 }
 
 TEST_F(CompilerTest, RespectTargetEnvOnVulkanShader) {
-  compiler_.SetMessageRules(kVulkanRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);
   EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));
 }
 
 TEST_F(CompilerTest, VulkanSpecificShaderFailsUnderOpenGLCompatibilityRules) {
-  compiler_.SetMessageRules(kOpenGLCompatibilityRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);
   EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));
 }
 
 TEST_F(CompilerTest, VulkanSpecificShaderFailsUnderOpenGLRules) {
-  compiler_.SetMessageRules(kOpenGLRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);
   EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));
 }
 
@@ -247,13 +240,13 @@
 }
 
 TEST_F(CompilerTest, OpenGLCompatibilitySpecificShaderFailsUnderVulkanRules) {
-  compiler_.SetMessageRules(kVulkanRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);
   EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader,
                                          EShLangFragment));
 }
 
 TEST_F(CompilerTest, OpenGLSpecificShaderFailsUnderVulkanRules) {
-  compiler_.SetMessageRules(kVulkanRules);
+  compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);
   EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLVertexShader, EShLangVertex));
 }
 
diff --git a/libshaderc_util/src/spirv_tools_wrapper.cc b/libshaderc_util/src/spirv_tools_wrapper.cc
index b6bff02..273d1ba 100644
--- a/libshaderc_util/src/spirv_tools_wrapper.cc
+++ b/libshaderc_util/src/spirv_tools_wrapper.cc
@@ -21,7 +21,25 @@
 
 namespace shaderc_util {
 
-bool SpirvToolsDisassemble(const std::vector<uint32_t>& binary,
+namespace {
+
+// Gets the corresponding target environment used in SPIRV-Tools.
+spv_target_env GetSpirvToolsTargetEnv(Compiler::TargetEnv env) {
+  switch (env) {
+    case Compiler::TargetEnv::Vulkan:
+      return SPV_ENV_VULKAN_1_0;
+    case Compiler::TargetEnv::OpenGL:
+      return SPV_ENV_OPENGL_4_5;
+    case Compiler::TargetEnv::OpenGLCompat:
+      return SPV_ENV_OPENGL_4_5;  // TODO(antiagainst): is this correct?
+  }
+  return SPV_ENV_VULKAN_1_0;
+}
+
+}  // anonymous namespace
+
+bool SpirvToolsDisassemble(Compiler::TargetEnv env,
+                           const std::vector<uint32_t>& binary,
                            std::string* text_or_error) {
   spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
   std::ostringstream oss;
@@ -37,9 +55,9 @@
   return success;
 }
 
-bool SpirvToolsAssemble(const string_piece assembly, spv_binary* binary,
-                        std::string* errors) {
-  auto spvtools_context = spvContextCreate(SPV_ENV_VULKAN_1_0);
+bool SpirvToolsAssemble(Compiler::TargetEnv env, const string_piece assembly,
+                        spv_binary* binary, std::string* errors) {
+  auto spvtools_context = spvContextCreate(GetSpirvToolsTargetEnv(env));
   spv_diagnostic spvtools_diagnostic = nullptr;
 
   *binary = nullptr;
@@ -62,7 +80,8 @@
   return success;
 }
 
-bool SpirvToolsOptimize(const std::vector<PassId>& enabled_passes,
+bool SpirvToolsOptimize(Compiler::TargetEnv env,
+                        const std::vector<PassId>& enabled_passes,
                         std::vector<uint32_t>* binary, std::string* errors) {
   errors->clear();
   if (enabled_passes.empty()) return true;
@@ -72,7 +91,7 @@
     return true;
   }
 
-  spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_0);
+  spvtools::Optimizer optimizer(GetSpirvToolsTargetEnv(env));
   std::ostringstream oss;
   optimizer.SetMessageConsumer(
       [&oss](spv_message_level_t, const char*, const spv_position_t&,