bool cmQtAutoMocUicT::InitFromInfo()

in Source/cmQtAutoMocUic.cxx [2380:2812]


bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
{
  // -- Required settings
  if (!info.GetBool("MULTI_CONFIG", this->BaseConst_.MultiConfig, true) ||
      !info.GetBool("CROSS_CONFIG", this->BaseConst_.CrossConfig, true) ||
      !info.GetBool("USE_BETTER_GRAPH", this->BaseConst_.UseBetterGraph,
                    true) ||
      !info.GetUInt("QT_VERSION_MAJOR", this->BaseConst_.QtVersion.Major,
                    true) ||
      !info.GetUInt("QT_VERSION_MINOR", this->BaseConst_.QtVersion.Minor,
                    true) ||
      !info.GetUInt("PARALLEL", this->BaseConst_.ThreadCount, false) ||
#ifdef _WIN32
      !info.GetUInt("AUTOGEN_COMMAND_LINE_LENGTH_MAX",
                    this->BaseConst_.MaxCommandLineLength, false) ||
#endif
      !info.GetString("BUILD_DIR", this->BaseConst_.AutogenBuildDir, true) ||
      !info.GetStringConfig("INCLUDE_DIR", this->BaseConst_.AutogenIncludeDir,
                            true) ||
      !info.GetString("CMAKE_EXECUTABLE", this->BaseConst_.CMakeExecutable,
                      true) ||
      !info.GetStringConfig("PARSE_CACHE_FILE",
                            this->BaseConst_.ParseCacheFile, true) ||
      !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) ||
      !info.GetArray("CMAKE_LIST_FILES", this->BaseConst_.ListFiles, true) ||
      !info.GetArray("HEADER_EXTENSIONS", this->BaseConst_.HeaderExtensions,
                     true)) {
    return false;
  }
  if (this->BaseConst().UseBetterGraph) {
    if (!info.GetStringConfig("DEP_FILE", this->BaseConst_.DepFile, false) ||
        !info.GetStringConfig("DEP_FILE_RULE_NAME",
                              this->BaseConst_.DepFileRuleName, false)) {
      return false;
    }

    if (this->BaseConst_.CrossConfig) {
      std::string const mocExecutableWithConfig =
        "QT_MOC_EXECUTABLE_" + this->ExecutableConfig();
      std::string const uicExecutableWithConfig =
        "QT_UIC_EXECUTABLE_" + this->ExecutableConfig();
      if (!info.GetString(mocExecutableWithConfig, this->MocConst_.Executable,
                          false) ||
          !info.GetString(uicExecutableWithConfig, this->UicConst_.Executable,
                          false)) {
        return false;
      }
    } else {
      if (!info.GetStringConfig("QT_MOC_EXECUTABLE",
                                this->MocConst_.Executable, false) ||
          !info.GetStringConfig("QT_UIC_EXECUTABLE",
                                this->UicConst_.Executable, false)) {
        return false;
      }
    }
  } else {
    if (!info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable,
                        false) ||
        !info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable,
                        false) ||
        !info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) ||
        !info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName,
                        false)) {
      return false;
    }
  }

  // -- Checks
  if (!this->BaseConst_.CMakeExecutableTime.Load(
        this->BaseConst_.CMakeExecutable)) {
    return info.LogError(
      cmStrCat("The CMake executable ",
               this->MessagePath(this->BaseConst_.CMakeExecutable),
               " does not exist."));
  }

  // -- Evaluate values
  this->BaseConst_.ThreadCount =
    std::min(this->BaseConst_.ThreadCount, ParallelMax);
  this->WorkerPool_.SetThreadCount(this->BaseConst_.ThreadCount);

  // -- Moc
  if (!this->MocConst_.Executable.empty()) {
    // -- Moc is enabled
    this->MocConst_.Enabled = true;

    // -- Temporary buffers
    struct
    {
      std::vector<std::string> MacroNames;
      std::vector<std::string> DependFilters;
    } tmp;

    // -- Required settings
    if (!info.GetBool("MOC_RELAXED_MODE", this->MocConst_.RelaxedMode,
                      false) ||
        !info.GetBool("MOC_PATH_PREFIX", this->MocConst_.PathPrefix, true) ||
        !info.GetArray("MOC_SKIP", this->MocConst_.SkipList, false) ||
        !info.GetArrayConfig("MOC_DEFINITIONS", this->MocConst_.Definitions,
                             false) ||
        !info.GetArrayConfig("MOC_INCLUDES", this->MocConst_.IncludePaths,
                             false) ||
        !info.GetArray("MOC_OPTIONS", this->MocConst_.OptionsExtra, false) ||
        !info.GetStringConfig("MOC_COMPILATION_FILE",
                              this->MocConst_.CompFileAbs, true) ||
        !info.GetArray("MOC_PREDEFS_CMD", this->MocConst_.PredefsCmd, false) ||
        !info.GetStringConfig("MOC_PREDEFS_FILE",
                              this->MocConst_.PredefsFileAbs,
                              !this->MocConst_.PredefsCmd.empty()) ||
        !info.GetArray("MOC_MACRO_NAMES", tmp.MacroNames, true) ||
        !info.GetArray("MOC_DEPEND_FILTERS", tmp.DependFilters, false)) {
      return false;
    }

    // -- Evaluate settings
    for (std::string const& item : tmp.MacroNames) {
      this->MocConst_.MacroFilters.emplace_back(
        item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
    }
    // Can moc output dependencies or do we need to setup dependency filters?
    if (this->BaseConst_.QtVersion >= IntegerVersion(5, 15)) {
      this->MocConst_.CanOutputDependencies = true;
    } else {
      Json::Value const& val = info.GetValue("MOC_DEPEND_FILTERS");
      if (!val.isArray()) {
        return info.LogError("MOC_DEPEND_FILTERS JSON value is not an array.");
      }
      Json::ArrayIndex const arraySize = val.size();
      for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
        // Test entry closure
        auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
          if (!test) {
            info.LogError(
              cmStrCat("MOC_DEPEND_FILTERS filter ", ii, ": ", msg));
          }
          return !test;
        };

        Json::Value const& pairVal = val[ii];

        if (testEntry(pairVal.isArray(), "JSON value is not an array.") ||
            testEntry(pairVal.size() == 2, "JSON array size invalid.")) {
          return false;
        }

        Json::Value const& keyVal = pairVal[0u];
        Json::Value const& expVal = pairVal[1u];
        if (testEntry(keyVal.isString(),
                      "JSON value for keyword is not a string.") ||
            testEntry(expVal.isString(),
                      "JSON value for regular expression is not a string.")) {
          return false;
        }

        std::string const key = keyVal.asString();
        std::string const exp = expVal.asString();
        if (testEntry(!key.empty(), "Keyword is empty.") ||
            testEntry(!exp.empty(), "Regular expression is empty.")) {
          return false;
        }

        this->MocConst_.DependFilters.emplace_back(key, exp);
        if (testEntry(
              this->MocConst_.DependFilters.back().Exp.is_valid(),
              cmStrCat("Regular expression compilation failed.\nKeyword: ",
                       Quoted(key), "\nExpression: ", Quoted(exp)))) {
          return false;
        }
      }
    }
    // Check if moc executable exists (by reading the file time)
    if (!this->MocConst_.ExecutableTime.Load(this->MocConst_.Executable)) {
      return info.LogError(cmStrCat(
        "The moc executable ", this->MessagePath(this->MocConst_.Executable),
        " does not exist."));
    }
  }

  // -- Uic
  if (!this->UicConst_.Executable.empty()) {
    // Uic is enabled
    this->UicConst_.Enabled = true;

    // -- Required settings
    if (!info.GetArray("UIC_SKIP", this->UicConst_.SkipList, false) ||
        !info.GetArray("UIC_SEARCH_PATHS", this->UicConst_.SearchPaths,
                       false) ||
        !info.GetArrayConfig("UIC_OPTIONS", this->UicConst_.Options, false)) {
      return false;
    }
    // .ui files
    {
      Json::Value const& val = info.GetValue("UIC_UI_FILES");
      if (!val.isArray()) {
        return info.LogError("UIC_UI_FILES JSON value is not an array.");
      }
      Json::ArrayIndex const arraySize = val.size();
      for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
        // Test entry closure
        auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
          if (!test) {
            info.LogError(cmStrCat("UIC_UI_FILES entry ", ii, ": ", msg));
          }
          return !test;
        };

        Json::Value const& entry = val[ii];
        if (testEntry(entry.isArray(), "JSON value is not an array.") ||
            testEntry(entry.size() == 2, "JSON array size invalid.")) {
          return false;
        }

        Json::Value const& entryName = entry[0u];
        Json::Value const& entryOptions = entry[1u];
        if (testEntry(entryName.isString(),
                      "JSON value for name is not a string.") ||
            testEntry(entryOptions.isArray(),
                      "JSON value for options is not an array.")) {
          return false;
        }

        auto& uiFile = this->UicConst_.UiFiles[entryName.asString()];
        InfoT::GetJsonArray(uiFile.Options, entryOptions);
      }
    }

    // -- Evaluate settings
    // Check if uic executable exists (by reading the file time)
    if (!this->UicConst_.ExecutableTime.Load(this->UicConst_.Executable)) {
      return info.LogError(cmStrCat(
        "The uic executable ", this->MessagePath(this->UicConst_.Executable),
        " does not exist."));
    }
  }

  // -- Headers
  {
    Json::Value const& val = info.GetValue("HEADERS");
    if (!val.isArray()) {
      return info.LogError("HEADERS JSON value is not an array.");
    }
    Json::ArrayIndex const arraySize = val.size();
    for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
      // Test entry closure
      auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
        if (!test) {
          info.LogError(cmStrCat("HEADERS entry ", ii, ": ", msg));
        }
        return !test;
      };

      Json::Value const& entry = val[ii];
      if (testEntry(entry.isArray(), "JSON value is not an array.") ||
          testEntry(entry.size() == 4, "JSON array size invalid.")) {
        return false;
      }

      Json::Value const& entryName = entry[0u];
      Json::Value const& entryFlags = entry[1u];
      Json::Value const& entryBuild = entry[2u];
      Json::Value const& entryConfigs = entry[3u];
      if (testEntry(entryName.isString(),
                    "JSON value for name is not a string.") ||
          testEntry(entryFlags.isString(),
                    "JSON value for flags is not a string.") ||
          testEntry(entryConfigs.isNull() || entryConfigs.isArray(),
                    "JSON value for configs is not null or array.") ||
          testEntry(entryBuild.isString(),
                    "JSON value for build path is not a string.")) {
        return false;
      }

      std::string name = entryName.asString();
      std::string flags = entryFlags.asString();
      std::string build = entryBuild.asString();
      if (testEntry(flags.size() == 2, "Invalid flags string size")) {
        return false;
      }

      if (entryConfigs.isArray()) {
        bool configFound = false;
        Json::ArrayIndex const configArraySize = entryConfigs.size();
        for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) {
          Json::Value const& config = entryConfigs[ci];
          if (testEntry(config.isString(),
                        "JSON value in config array is not a string.")) {
            return false;
          }
          configFound = configFound || config.asString() == this->InfoConfig();
        }
        if (!configFound) {
          continue;
        }
      }

      cmFileTime fileTime;
      if (!fileTime.Load(name)) {
        return info.LogError(cmStrCat(
          "The header file ", this->MessagePath(name), " does not exist."));
      }

      SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(name);
      sourceHandle->FileTime = fileTime;
      sourceHandle->IsHeader = true;
      sourceHandle->Moc = (flags[0] == 'M');
      sourceHandle->Uic = (flags[1] == 'U');
      if (sourceHandle->Moc && this->MocConst().Enabled) {
        if (build.empty()) {
          return info.LogError(
            cmStrCat("Header file ", ii, " build path is empty"));
        }
        sourceHandle->BuildPath = std::move(build);
      }
      this->BaseEval().Headers.emplace(std::move(name),
                                       std::move(sourceHandle));
    }
  }

  // -- Sources
  {
    Json::Value const& val = info.GetValue("SOURCES");
    if (!val.isArray()) {
      return info.LogError("SOURCES JSON value is not an array.");
    }
    Json::ArrayIndex const arraySize = val.size();
    for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) {
      // Test entry closure
      auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool {
        if (!test) {
          info.LogError(cmStrCat("SOURCES entry ", ii, ": ", msg));
        }
        return !test;
      };

      Json::Value const& entry = val[ii];
      if (testEntry(entry.isArray(), "JSON value is not an array.") ||
          testEntry(entry.size() == 3, "JSON array size invalid.")) {
        return false;
      }

      Json::Value const& entryName = entry[0u];
      Json::Value const& entryFlags = entry[1u];
      Json::Value const& entryConfigs = entry[2u];
      if (testEntry(entryName.isString(),
                    "JSON value for name is not a string.") ||
          testEntry(entryFlags.isString(),
                    "JSON value for flags is not a string.") ||
          testEntry(entryConfigs.isNull() || entryConfigs.isArray(),
                    "JSON value for configs is not null or array.")) {
        return false;
      }

      std::string name = entryName.asString();
      std::string flags = entryFlags.asString();
      if (testEntry(flags.size() == 2, "Invalid flags string size")) {
        return false;
      }

      if (entryConfigs.isArray()) {
        bool configFound = false;
        Json::ArrayIndex const configArraySize = entryConfigs.size();
        for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) {
          Json::Value const& config = entryConfigs[ci];
          if (testEntry(config.isString(),
                        "JSON value in config array is not a string.")) {
            return false;
          }
          configFound = configFound || config.asString() == this->InfoConfig();
        }
        if (!configFound) {
          continue;
        }
      }

      cmFileTime fileTime;
      if (!fileTime.Load(name)) {
        return info.LogError(cmStrCat(
          "The source file ", this->MessagePath(name), " does not exist."));
      }

      SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(name);
      sourceHandle->FileTime = fileTime;
      sourceHandle->IsHeader = false;
      sourceHandle->Moc = (flags[0] == 'M');
      sourceHandle->Uic = (flags[1] == 'U');
      this->BaseEval().Sources.emplace(std::move(name),
                                       std::move(sourceHandle));
    }
  }

  // -- Init derived information
  // Moc variables
  if (this->MocConst().Enabled) {
    // Compose moc includes list
    {
      // Compute framework paths
      std::set<std::string> frameworkPaths;
      for (std::string const& path : this->MocConst().IncludePaths) {
        // Extract framework path
        if (cmHasLiteralSuffix(path, ".framework/Headers")) {
          // Go up twice to get to the framework root
          std::vector<std::string> pathComponents;
          cmSystemTools::SplitPath(path, pathComponents);
          frameworkPaths.emplace(cmSystemTools::JoinPath(
            pathComponents.begin(), pathComponents.end() - 2));
        }
      }
      // Reserve options
      this->MocConst_.OptionsIncludes.reserve(
        this->MocConst().IncludePaths.size() + frameworkPaths.size() * 2);
      // Append includes
      for (std::string const& path : this->MocConst().IncludePaths) {
        this->MocConst_.OptionsIncludes.emplace_back("-I" + path);
      }
      // Append framework includes
      for (std::string const& path : frameworkPaths) {
        this->MocConst_.OptionsIncludes.emplace_back("-F");
        this->MocConst_.OptionsIncludes.push_back(path);
      }
    }

    // Compose moc definitions list
    {
      this->MocConst_.OptionsDefinitions.reserve(
        this->MocConst().Definitions.size());
      for (std::string const& def : this->MocConst().Definitions) {
        this->MocConst_.OptionsDefinitions.emplace_back("-D" + def);
      }
    }
  }

  return true;
}