mirror of
https://github.com/reactos/CMake.git
synced 2025-02-01 17:42:41 +00:00
fc8b90af2c
Rather than taking a number of out parameters for the various names, create a structure that is reused for both `GetLibraryNames` and `GetExecutableNames`. Replace uses according to the new interface.
562 lines
19 KiB
C++
562 lines
19 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#include "cmGhsMultiTargetGenerator.h"
|
|
|
|
#include "cmComputeLinkInformation.h"
|
|
#include "cmGeneratedFileStream.h"
|
|
#include "cmGeneratorTarget.h"
|
|
#include "cmGlobalGhsMultiGenerator.h"
|
|
#include "cmLinkLineComputer.h"
|
|
#include "cmLocalGhsMultiGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmSourceGroup.h"
|
|
#include "cmTarget.h"
|
|
|
|
cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
|
|
: GeneratorTarget(target)
|
|
, LocalGenerator(
|
|
static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
|
|
, Makefile(target->Target->GetMakefile())
|
|
, Name(target->GetName())
|
|
{
|
|
// Store the configuration name that is being used
|
|
if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
|
|
// Use the build type given by the user.
|
|
this->ConfigName = config;
|
|
} else {
|
|
// No configuration type given.
|
|
this->ConfigName.clear();
|
|
}
|
|
}
|
|
|
|
cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
|
|
{
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::Generate()
|
|
{
|
|
// Determine type of target for this project
|
|
switch (this->GeneratorTarget->GetType()) {
|
|
case cmStateEnums::EXECUTABLE: {
|
|
// Get the name of the executable to generate.
|
|
this->TargetNameReal =
|
|
this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
|
|
if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
|
|
this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
|
|
} else {
|
|
this->TagType = GhsMultiGpj::PROGRAM;
|
|
}
|
|
break;
|
|
}
|
|
case cmStateEnums::STATIC_LIBRARY: {
|
|
this->TargetNameReal =
|
|
this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
|
|
this->TagType = GhsMultiGpj::LIBRARY;
|
|
break;
|
|
}
|
|
case cmStateEnums::SHARED_LIBRARY: {
|
|
std::string msg = "add_library(<name> SHARED ...) not supported: ";
|
|
msg += this->Name;
|
|
cmSystemTools::Message(msg);
|
|
return;
|
|
}
|
|
case cmStateEnums::OBJECT_LIBRARY: {
|
|
this->TargetNameReal =
|
|
this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
|
|
this->TagType = GhsMultiGpj::SUBPROJECT;
|
|
break;
|
|
}
|
|
case cmStateEnums::MODULE_LIBRARY: {
|
|
std::string msg = "add_library(<name> MODULE ...) not supported: ";
|
|
msg += this->Name;
|
|
cmSystemTools::Message(msg);
|
|
return;
|
|
}
|
|
case cmStateEnums::UTILITY: {
|
|
std::string msg = "add_custom_target(<name> ...) not supported: ";
|
|
msg += this->Name;
|
|
cmSystemTools::Message(msg);
|
|
return;
|
|
}
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// Tell the global generator the name of the project file
|
|
this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
|
|
this->Name.c_str());
|
|
this->GeneratorTarget->Target->SetProperty(
|
|
"GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
|
|
|
|
this->GenerateTarget();
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::GenerateTarget()
|
|
{
|
|
// Open the filestream in copy-if-different mode.
|
|
std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
|
|
fname += "/";
|
|
fname += this->Name;
|
|
fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
|
|
cmGeneratedFileStream fout(fname.c_str());
|
|
fout.SetCopyIfDifferent(true);
|
|
|
|
this->GetGlobalGenerator()->WriteFileHeader(fout);
|
|
GhsMultiGpj::WriteGpjTag(this->TagType, fout);
|
|
|
|
const std::string language(
|
|
this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
|
|
|
|
this->WriteTargetSpecifics(fout, this->ConfigName);
|
|
this->SetCompilerFlags(this->ConfigName, language);
|
|
this->WriteCompilerFlags(fout, this->ConfigName, language);
|
|
this->WriteCompilerDefinitions(fout, this->ConfigName, language);
|
|
this->WriteIncludes(fout, this->ConfigName, language);
|
|
this->WriteTargetLinkLine(fout, this->ConfigName);
|
|
this->WriteCustomCommands(fout);
|
|
this->WriteSources(fout);
|
|
this->WriteReferences(fout);
|
|
fout.Close();
|
|
}
|
|
|
|
cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
|
|
const
|
|
{
|
|
return static_cast<cmGlobalGhsMultiGenerator*>(
|
|
this->LocalGenerator->GetGlobalGenerator());
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout,
|
|
const std::string& config)
|
|
{
|
|
std::string outpath;
|
|
std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
|
|
|
|
if (this->TagType != GhsMultiGpj::SUBPROJECT) {
|
|
// set target binary file destination
|
|
outpath = this->GeneratorTarget->GetDirectory(config);
|
|
outpath =
|
|
this->LocalGenerator->MaybeConvertToRelativePath(rootpath, outpath);
|
|
fout << " :binDirRelative=\"" << outpath << "\"" << std::endl;
|
|
fout << " -o \"" << this->TargetNameReal << "\"" << std::endl;
|
|
}
|
|
|
|
// set target object file destination
|
|
outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
|
|
fout << " :outputDirRelative=\"" << outpath << "\"" << std::endl;
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
|
|
const std::string& language)
|
|
{
|
|
std::map<std::string, std::string>::iterator i =
|
|
this->FlagsByLanguage.find(language);
|
|
if (i == this->FlagsByLanguage.end()) {
|
|
std::string flags;
|
|
const char* lang = language.c_str();
|
|
|
|
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, lang,
|
|
config);
|
|
|
|
this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang,
|
|
config);
|
|
this->LocalGenerator->AddVisibilityPresetFlags(
|
|
flags, this->GeneratorTarget, lang);
|
|
|
|
// Append old-style preprocessor definition flags.
|
|
if (this->Makefile->GetDefineFlags() != " ") {
|
|
this->LocalGenerator->AppendFlags(flags,
|
|
this->Makefile->GetDefineFlags());
|
|
}
|
|
|
|
// Add target-specific flags.
|
|
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, lang,
|
|
config);
|
|
|
|
std::map<std::string, std::string>::value_type entry(language, flags);
|
|
i = this->FlagsByLanguage.insert(entry).first;
|
|
}
|
|
}
|
|
|
|
std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language,
|
|
std::string const& config)
|
|
{
|
|
std::map<std::string, std::string>::iterator i =
|
|
this->DefinesByLanguage.find(language);
|
|
if (i == this->DefinesByLanguage.end()) {
|
|
std::set<std::string> defines;
|
|
const char* lang = language.c_str();
|
|
// Add preprocessor definitions for this target and configuration.
|
|
this->LocalGenerator->GetTargetDefines(this->GeneratorTarget, config,
|
|
language, defines);
|
|
|
|
std::string definesString;
|
|
this->LocalGenerator->JoinDefines(defines, definesString, lang);
|
|
|
|
std::map<std::string, std::string>::value_type entry(language,
|
|
definesString);
|
|
i = this->DefinesByLanguage.insert(entry).first;
|
|
}
|
|
return i->second;
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout,
|
|
std::string const&,
|
|
const std::string& language)
|
|
{
|
|
std::map<std::string, std::string>::iterator flagsByLangI =
|
|
this->FlagsByLanguage.find(language);
|
|
if (flagsByLangI != this->FlagsByLanguage.end()) {
|
|
if (!flagsByLangI->second.empty()) {
|
|
std::vector<std::string> ghsCompFlags =
|
|
cmSystemTools::ParseArguments(flagsByLangI->second.c_str());
|
|
for (auto& f : ghsCompFlags) {
|
|
fout << " " << f << std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
|
|
std::ostream& fout, const std::string& config, const std::string& language)
|
|
{
|
|
std::vector<std::string> compileDefinitions;
|
|
this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
|
|
language);
|
|
for (std::string const& compileDefinition : compileDefinitions) {
|
|
fout << " -D" << compileDefinition << std::endl;
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout,
|
|
const std::string& config,
|
|
const std::string& language)
|
|
{
|
|
std::vector<std::string> includes;
|
|
this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
|
|
language, config);
|
|
|
|
for (std::string const& include : includes) {
|
|
fout << " -I\"" << include << "\"" << std::endl;
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
|
|
std::string const& config)
|
|
{
|
|
if (this->TagType == GhsMultiGpj::INTERGRITY_APPLICATION) {
|
|
return;
|
|
}
|
|
|
|
std::string linkLibraries;
|
|
std::string flags;
|
|
std::string linkFlags;
|
|
std::string frameworkPath;
|
|
std::string linkPath;
|
|
|
|
std::unique_ptr<cmLinkLineComputer> linkLineComputer(
|
|
this->GetGlobalGenerator()->CreateLinkLineComputer(
|
|
this->LocalGenerator,
|
|
this->LocalGenerator->GetStateSnapshot().GetDirectory()));
|
|
|
|
this->LocalGenerator->GetTargetFlags(
|
|
linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
|
|
frameworkPath, linkPath, this->GeneratorTarget);
|
|
|
|
// write out link options
|
|
std::vector<std::string> lopts =
|
|
cmSystemTools::ParseArguments(linkFlags.c_str());
|
|
for (auto& l : lopts) {
|
|
fout << " " << l << std::endl;
|
|
}
|
|
|
|
// write out link search paths
|
|
// must be quoted for paths that contain spaces
|
|
std::vector<std::string> lpath =
|
|
cmSystemTools::ParseArguments(linkPath.c_str());
|
|
for (auto& l : lpath) {
|
|
fout << " -L\"" << l << "\"" << std::endl;
|
|
}
|
|
|
|
// write out link libs
|
|
// must be quoted for filepaths that contains spaces
|
|
std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
|
|
|
|
std::vector<std::string> llibs =
|
|
cmSystemTools::ParseArguments(linkLibraries.c_str());
|
|
for (auto& l : llibs) {
|
|
if (l.compare(0, 2, "-l") == 0) {
|
|
fout << " \"" << l << "\"" << std::endl;
|
|
} else {
|
|
std::string rl = cmSystemTools::CollapseCombinedPath(cbd, l);
|
|
fout << " -l\"" << rl << "\"" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout)
|
|
{
|
|
WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(),
|
|
cmTarget::PRE_BUILD);
|
|
WriteCustomCommandsHelper(
|
|
fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD);
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
|
|
std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
|
|
cmTarget::CustomCommandType const commandType)
|
|
{
|
|
for (cmCustomCommand const& customCommand : commandsSet) {
|
|
cmCustomCommandLines const& commandLines = customCommand.GetCommandLines();
|
|
for (cmCustomCommandLine const& command : commandLines) {
|
|
switch (commandType) {
|
|
case cmTarget::PRE_BUILD:
|
|
fout << " :preexecShellSafe=";
|
|
break;
|
|
case cmTarget::POST_BUILD:
|
|
fout << " :postexecShellSafe=";
|
|
break;
|
|
default:
|
|
assert("Only pre and post are supported");
|
|
}
|
|
|
|
bool firstIteration = true;
|
|
for (std::string const& commandLine : command) {
|
|
std::string subCommandE =
|
|
this->LocalGenerator->EscapeForShell(commandLine, true);
|
|
fout << (firstIteration ? "'" : " ");
|
|
// Need to double escape backslashes
|
|
cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
|
|
fout << subCommandE;
|
|
firstIteration = false;
|
|
}
|
|
if (!command.empty()) {
|
|
fout << "'" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout,
|
|
const cmSourceFile* sf,
|
|
std::string propName,
|
|
std::string propFlag)
|
|
{
|
|
const char* prop = sf->GetProperty(propName);
|
|
if (prop) {
|
|
std::vector<std::string> list;
|
|
cmSystemTools::ExpandListArgument(prop, list);
|
|
for (auto& p : list) {
|
|
fout << " " << propFlag << p << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
|
|
{
|
|
/* vector of all sources for this target */
|
|
std::vector<cmSourceFile*> sources;
|
|
this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
|
|
|
|
/* vector of all groups defined for this target
|
|
* -- but the vector is not expanded with sub groups or in any useful order
|
|
*/
|
|
std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
|
|
|
|
/* for each source file assign it to its group */
|
|
std::map<std::string, std::vector<cmSourceFile*>> groupFiles;
|
|
std::set<std::string> groupNames;
|
|
for (auto& sf : sources) {
|
|
cmSourceGroup* sourceGroup =
|
|
this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups);
|
|
std::string gn = sourceGroup->GetFullName();
|
|
groupFiles[gn].push_back(sf);
|
|
groupNames.insert(gn);
|
|
}
|
|
|
|
/* list of known groups and the order they are displayed in a project file */
|
|
const std::vector<std::string> standardGroups = {
|
|
"Header Files", "Source Files", "CMake Rules",
|
|
"Object Files", "Object Libraries", "Resources"
|
|
};
|
|
|
|
/* list of groups in the order they are displayed in a project file*/
|
|
std::vector<std::string> groupFilesList(groupFiles.size());
|
|
|
|
/* put the groups in the order they should be listed
|
|
* - standard groups first, and then everything else
|
|
* in the order used by std::map.
|
|
*/
|
|
int i = 0;
|
|
for (const std::string& gn : standardGroups) {
|
|
auto n = groupNames.find(gn);
|
|
if (n != groupNames.end()) {
|
|
groupFilesList[i] = *n;
|
|
i += 1;
|
|
groupNames.erase(gn);
|
|
}
|
|
}
|
|
|
|
{ /* catch-all group - is last item */
|
|
std::string gn = "";
|
|
auto n = groupNames.find(gn);
|
|
if (n != groupNames.end()) {
|
|
groupFilesList.back() = *n;
|
|
groupNames.erase(gn);
|
|
}
|
|
}
|
|
|
|
for (auto& n : groupNames) {
|
|
groupFilesList[i] = n;
|
|
i += 1;
|
|
}
|
|
|
|
/* sort the files within each group */
|
|
for (auto& n : groupFilesList) {
|
|
std::sort(groupFiles[n].begin(), groupFiles[n].end(),
|
|
[](cmSourceFile* l, cmSourceFile* r) {
|
|
return l->GetFullPath() < r->GetFullPath();
|
|
});
|
|
}
|
|
|
|
/* list of open project files */
|
|
std::vector<cmGeneratedFileStream*> gfiles;
|
|
|
|
/* write files into the proper project file
|
|
* -- groups go into main project file
|
|
* unless FOLDER property or variable is set.
|
|
*/
|
|
for (auto& sg : groupFilesList) {
|
|
std::ostream* fout;
|
|
bool useProjectFile =
|
|
cmSystemTools::IsOn(
|
|
this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) ||
|
|
cmSystemTools::IsOn(
|
|
this->Makefile->GetDefinition("CMAKE_GHS_NO_SOURCE_GROUP_FILE"));
|
|
if (useProjectFile || sg.empty()) {
|
|
fout = &fout_proj;
|
|
} else {
|
|
// Open the filestream in copy-if-different mode.
|
|
std::string gname = sg;
|
|
cmsys::SystemTools::ReplaceString(gname, "\\", "_");
|
|
std::string lpath =
|
|
this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
|
|
lpath += "/";
|
|
lpath += gname;
|
|
lpath += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
|
|
std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory();
|
|
fpath += "/";
|
|
fpath += lpath;
|
|
cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str());
|
|
f->SetCopyIfDifferent(true);
|
|
gfiles.push_back(f);
|
|
fout = f;
|
|
this->GetGlobalGenerator()->WriteFileHeader(*f);
|
|
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, *f);
|
|
fout_proj << lpath << " ";
|
|
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, fout_proj);
|
|
}
|
|
|
|
if (useProjectFile) {
|
|
if (sg.empty()) {
|
|
*fout << "{comment} Others" << std::endl;
|
|
} else {
|
|
*fout << "{comment} " << sg << std::endl;
|
|
}
|
|
}
|
|
|
|
/* output rule for each source file */
|
|
for (const cmSourceFile* si : groupFiles[sg]) {
|
|
|
|
// Convert filename to native system
|
|
// WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
|
|
// windows when opening some files from the search window.
|
|
std::string fname(si->GetFullPath());
|
|
cmSystemTools::ConvertToOutputSlashes(fname);
|
|
*fout << fname << std::endl;
|
|
|
|
if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
|
|
"bsp" != si->GetExtension()) {
|
|
this->WriteObjectLangOverride(*fout, si);
|
|
}
|
|
|
|
this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
|
|
this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
|
|
this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
|
|
|
|
/* to avoid clutter in the gui only print out the objectName if it has
|
|
* been renamed */
|
|
std::string objectName = this->GeneratorTarget->GetObjectName(si);
|
|
if (!objectName.empty() &&
|
|
this->GeneratorTarget->HasExplicitObjectName(si)) {
|
|
*fout << " -o " << objectName << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (cmGeneratedFileStream* f : gfiles) {
|
|
f->Close();
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
|
|
std::ostream& fout, const cmSourceFile* sourceFile)
|
|
{
|
|
const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
|
|
if (NULL != rawLangProp) {
|
|
std::string sourceLangProp(rawLangProp);
|
|
std::string extension(sourceFile->GetExtension());
|
|
if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
|
|
fout << " -dotciscxx" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout)
|
|
{
|
|
// This only applies to INTEGRITY Applications
|
|
if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) {
|
|
return;
|
|
}
|
|
|
|
// Get the targets that this one depends upon
|
|
cmTargetDependSet unordered =
|
|
this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
|
|
cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered,
|
|
this->Name);
|
|
for (auto& t : ordered) {
|
|
std::string tname = t->GetName();
|
|
std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory();
|
|
std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
|
|
std::string outpath =
|
|
this->LocalGenerator->MaybeConvertToRelativePath(rootpath, tpath) + "/" +
|
|
tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
|
|
|
|
fout << outpath;
|
|
fout << " ";
|
|
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout);
|
|
|
|
// Tell the global generator that a refernce project needs to be created
|
|
t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON");
|
|
}
|
|
}
|
|
|
|
bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void)
|
|
{
|
|
const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
|
|
if (p) {
|
|
return cmSystemTools::IsOn(
|
|
this->GeneratorTarget->GetProperty("ghs_integrity_app"));
|
|
} else {
|
|
std::vector<cmSourceFile*> sources;
|
|
this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
|
|
for (auto& sf : sources) {
|
|
if ("int" == sf->GetExtension()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|