diff options
author | Mateusz Janek <stryku2393@gmail.com> | 2016-12-21 15:27:49 +0100 |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2017-01-16 10:52:48 -0500 |
commit | b42330be21c0d3046aa0e6fdf046a492bddef520 (patch) | |
tree | efd6fbbda9401a36000f2c3b265b9d43310348e6 | |
parent | 6154a2cddcdb297b1aef20f501fec9af7d7b5262 (diff) | |
download | cmake-b42330be21c0d3046aa0e6fdf046a492bddef520.tar.gz |
source_group: Add options create groups matching directory tree
Add `TREE` and `PREFIX` arguments to enable this behavior.
-rw-r--r-- | Help/command/source_group.rst | 18 | ||||
-rw-r--r-- | Help/release/dev/source_group-tree.rst | 5 | ||||
-rw-r--r-- | Source/cmSourceGroupCommand.cxx | 165 | ||||
-rw-r--r-- | Source/cmSourceGroupCommand.h | 6 | ||||
-rw-r--r-- | Tests/SourceGroups/CMakeLists.txt | 13 | ||||
-rw-r--r-- | Tests/SourceGroups/main.c | 7 | ||||
-rw-r--r-- | Tests/SourceGroups/sub1/tree_bar.c | 4 | ||||
-rw-r--r-- | Tests/SourceGroups/sub1/tree_baz.c | 4 | ||||
-rw-r--r-- | Tests/SourceGroups/sub1/tree_subdir/tree_foobar.c | 4 | ||||
-rw-r--r-- | Tests/SourceGroups/tree_foo.c | 4 |
10 files changed, 227 insertions, 3 deletions
diff --git a/Help/command/source_group.rst b/Help/command/source_group.rst index 6e3829c044..938ca40f2b 100644 --- a/Help/command/source_group.rst +++ b/Help/command/source_group.rst @@ -2,15 +2,27 @@ source_group ------------ Define a grouping for source files in IDE project generation. +There are two different signatures to create source groups. -.. code-block:: cmake +:: source_group(<name> [FILES <src>...] [REGULAR_EXPRESSION <regex>]) + source_group(TREE <root> [PREFIX <prefix>] [FILES <src>...]) Defines a group into which sources will be placed in project files. This is intended to set up file tabs in Visual Studio. The options are: +``TREE`` + CMake will automatically detect, from ``<src>`` files paths, source groups + it needs to create, to keep structure of source groups analogically to the + actual files and directories structure in the project. Paths of ``<src>`` + files will be cut to be relative to ``<root>``. + +``PREFIX`` + Source group and files located directly in ``<root>`` path, will be placed + in ``<prefix>`` source groups. + ``FILES`` Any source file specified explicitly will be placed in group ``<name>``. Relative paths are interpreted with respect to the @@ -25,11 +37,13 @@ explicitly lists the file with ``FILES`` will be favored, if any. If no group explicitly lists the file, the *last* group whose regular expression matches the file will be favored. -The ``<name>`` of the group may contain backslashes to specify subgroups: +The ``<name>`` of the group and ``<prefix>`` argument may contain backslashes +to specify subgroups: .. code-block:: cmake source_group(outer\\inner ...) + source_group(TREE <root> PREFIX sources\\inc ...) For backwards compatibility, the short-hand signature diff --git a/Help/release/dev/source_group-tree.rst b/Help/release/dev/source_group-tree.rst new file mode 100644 index 0000000000..c5fec1dc00 --- /dev/null +++ b/Help/release/dev/source_group-tree.rst @@ -0,0 +1,5 @@ +source_group-tree +----------------- + +* The :command:`source_group` command gained ``TREE`` and ``PREFIX`` + options to add groups following source tree directory structure. diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 3f20d4e056..5555199088 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -8,6 +8,99 @@ #include "cmSourceGroup.h" #include "cmSystemTools.h" +namespace { +const size_t RootIndex = 1; +const size_t FilesWithoutPrefixKeywordIndex = 2; +const size_t FilesWithPrefixKeywordIndex = 4; +const size_t PrefixKeywordIdex = 2; + +std::vector<std::string> tokenizePath(const std::string& path) +{ + return cmSystemTools::tokenize(path, "\\/"); +} + +std::string getFullFilePath(const std::string& currentPath, + const std::string& path) +{ + std::string fullPath = path; + + if (!cmSystemTools::FileIsFullPath(path.c_str())) { + fullPath = currentPath; + fullPath += "/"; + fullPath += path; + } + + return cmSystemTools::CollapseFullPath(fullPath); +} + +std::set<std::string> getSourceGroupFilesPaths( + const std::string& currentPath, const std::string& root, + const std::vector<std::string>& files) +{ + std::set<std::string> ret; + const std::string::size_type rootLength = root.length(); + + for (size_t i = 0; i < files.size(); ++i) { + const std::string fullPath = getFullFilePath(currentPath, files[i]); + + ret.insert(fullPath.substr(rootLength + 1)); // +1 to also omnit last '/' + } + + return ret; +} + +cmSourceGroup* addSourceGroup(const std::vector<std::string>& tokenizedPath, + cmMakefile& makefile) +{ + cmSourceGroup* sg; + + sg = makefile.GetSourceGroup(tokenizedPath); + if (!sg) { + makefile.AddSourceGroup(tokenizedPath); + sg = makefile.GetSourceGroup(tokenizedPath); + if (!sg) { + return CM_NULLPTR; + } + } + + return sg; +} + +bool addFilesToItsSourceGroups(const std::set<std::string>& sgFilesPaths, + const std::string& prefix, cmMakefile& makefile, + std::string& errorMsg) +{ + cmSourceGroup* sg; + + for (std::set<std::string>::const_iterator it = sgFilesPaths.begin(); + it != sgFilesPaths.end(); ++it) { + + std::vector<std::string> tokenizedPath; + if (!prefix.empty()) { + tokenizedPath = tokenizePath(prefix + '/' + *it); + } else { + tokenizedPath = tokenizePath(*it); + } + + if (tokenizedPath.size() > 1) { + tokenizedPath.pop_back(); + + sg = addSourceGroup(tokenizedPath, makefile); + + if (!sg) { + errorMsg = "Could not create source group for file: " + *it; + return false; + } + const std::string fullPath = + getFullFilePath(makefile.GetCurrentSourceDirectory(), *it); + sg->AddGroupFile(fullPath); + } + } + + return true; +} +} + class cmExecutionStatus; // cmSourceGroupCommand @@ -19,6 +112,17 @@ bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, return false; } + if (args[0] == "TREE") { + std::string error; + + if (!processTree(args, error)) { + this->SetError(error); + return false; + } + + return true; + } + std::string delimiter = "\\"; if (this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER")) { delimiter = this->Makefile->GetDefinition("SOURCE_GROUP_DELIMITER"); @@ -82,3 +186,64 @@ bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, return true; } + +bool cmSourceGroupCommand::checkTreeArgumentsPreconditions( + const std::vector<std::string>& args, std::string& errorMsg) const +{ + if (args.size() == 1) { + errorMsg = "TREE argument given without a root."; + return false; + } + + if (args.size() < 3) { + errorMsg = "Missing FILES arguments."; + return false; + } + + if (args[FilesWithoutPrefixKeywordIndex] != "FILES" && + args[PrefixKeywordIdex] != "PREFIX") { + errorMsg = "Unknown argument \"" + args[2] + + "\". Perhaps the FILES keyword is missing.\n"; + return false; + } + + if (args[PrefixKeywordIdex] == "PREFIX" && + (args.size() < 5 || args[FilesWithPrefixKeywordIndex] != "FILES")) { + errorMsg = "Missing FILES arguments."; + return false; + } + + return true; +} + +bool cmSourceGroupCommand::processTree(const std::vector<std::string>& args, + std::string& errorMsg) +{ + if (!checkTreeArgumentsPreconditions(args, errorMsg)) { + return false; + } + + const std::string root = cmSystemTools::CollapseFullPath(args[RootIndex]); + std::string prefix; + size_t filesBegin = FilesWithoutPrefixKeywordIndex + 1; + if (args[PrefixKeywordIdex] == "PREFIX") { + prefix = args[PrefixKeywordIdex + 1]; + filesBegin = FilesWithPrefixKeywordIndex + 1; + } + + const std::vector<std::string> filesVector(args.begin() + filesBegin, + args.end()); + + std::set<std::string> sourceGroupPaths = getSourceGroupFilesPaths( + this->Makefile->GetCurrentSourceDirectory(), root, filesVector); + + addFilesToItsSourceGroups(sourceGroupPaths, prefix, *(this->Makefile), + errorMsg); + + if (!errorMsg.empty()) { + this->SetError(errorMsg); + return false; + } + + return true; +} diff --git a/Source/cmSourceGroupCommand.h b/Source/cmSourceGroupCommand.h index f533be15ca..55490963e5 100644 --- a/Source/cmSourceGroupCommand.h +++ b/Source/cmSourceGroupCommand.h @@ -36,6 +36,12 @@ public: * The name of the command as specified in CMakeList.txt. */ std::string GetName() const CM_OVERRIDE { return "source_group"; } + +private: + bool processTree(const std::vector<std::string>& args, + std::string& errorMsg); + bool checkTreeArgumentsPreconditions(const std::vector<std::string>& args, + std::string& errorMsg) const; }; #endif diff --git a/Tests/SourceGroups/CMakeLists.txt b/Tests/SourceGroups/CMakeLists.txt index 6573c8241b..9289e8444e 100644 --- a/Tests/SourceGroups/CMakeLists.txt +++ b/Tests/SourceGroups/CMakeLists.txt @@ -30,6 +30,17 @@ source_group(Base\\Sub1\\Base FILES bar.c) # a group without files, is currently not created source_group(EmptyGroup) +set(root ${CMAKE_CURRENT_SOURCE_DIR}) -add_executable(SourceGroups main.c bar.c foo.c sub1/foo.c sub1/foobar.c baz.c README.txt) +set(tree_files_without_prefix ${root}/sub1/tree_bar.c + ${root}/sub1/tree_baz.c + ${root}/sub1/tree_subdir/tree_foobar.c) +set(tree_files_with_prefix ${root}/tree_foo.c) + +source_group(TREE ${root} FILES ${tree_files_without_prefix}) + +source_group(TREE ${root} PREFIX tree_root/subgroup FILES ${tree_files_with_prefix}) + +add_executable(SourceGroups main.c bar.c foo.c sub1/foo.c sub1/foobar.c baz.c + ${tree_files_with_prefix} ${tree_files_without_prefix} README.txt) diff --git a/Tests/SourceGroups/main.c b/Tests/SourceGroups/main.c index f259f982f4..b88f2f8b3b 100644 --- a/Tests/SourceGroups/main.c +++ b/Tests/SourceGroups/main.c @@ -5,10 +5,17 @@ extern int bar(void); extern int foobar(void); extern int barbar(void); extern int baz(void); +extern int tree_foo(void); +extern int tree_bar(void); +extern int tree_foobar(void); +extern int tree_baz(void); int main() { printf("foo: %d bar: %d foobar: %d barbar: %d baz: %d\n", foo(), bar(), foobar(), barbar(), baz()); + + printf("tree_foo: %d tree_bar: %d tree_foobar: %d tree_baz: %d\n", + tree_foo(), tree_bar(), tree_foobar(), tree_baz()); return 0; } diff --git a/Tests/SourceGroups/sub1/tree_bar.c b/Tests/SourceGroups/sub1/tree_bar.c new file mode 100644 index 0000000000..6b79239bb8 --- /dev/null +++ b/Tests/SourceGroups/sub1/tree_bar.c @@ -0,0 +1,4 @@ +int tree_bar(void) +{ + return 8; +} diff --git a/Tests/SourceGroups/sub1/tree_baz.c b/Tests/SourceGroups/sub1/tree_baz.c new file mode 100644 index 0000000000..27ff5ab942 --- /dev/null +++ b/Tests/SourceGroups/sub1/tree_baz.c @@ -0,0 +1,4 @@ +int tree_baz(void) +{ + return 9; +} diff --git a/Tests/SourceGroups/sub1/tree_subdir/tree_foobar.c b/Tests/SourceGroups/sub1/tree_subdir/tree_foobar.c new file mode 100644 index 0000000000..e955e04ea2 --- /dev/null +++ b/Tests/SourceGroups/sub1/tree_subdir/tree_foobar.c @@ -0,0 +1,4 @@ +int tree_foobar(void) +{ + return 7; +} diff --git a/Tests/SourceGroups/tree_foo.c b/Tests/SourceGroups/tree_foo.c new file mode 100644 index 0000000000..d392e41fd3 --- /dev/null +++ b/Tests/SourceGroups/tree_foo.c @@ -0,0 +1,4 @@ +int tree_foo(void) +{ + return 6; +} |