From f5bcbeec0b06ad260e3b01c2d18f64c39696aebe Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Fri, 6 Jan 2023 23:39:56 +0000 Subject: [PATCH 01/11] Initial MSVC build working --- CMakeLists.txt | 68 ++++++++++++++----- src/class_diagram/model/class_parent.h | 2 - .../visitor/translation_unit_visitor.cc | 5 +- src/common/generators/plantuml/generator.h | 9 ++- src/common/model/diagram_filter.cc | 4 +- src/common/model/source_file.h | 2 +- src/common/visitor/translation_unit_visitor.h | 2 +- src/decorators/decorators.cc | 2 +- .../visitor/translation_unit_visitor.h | 2 +- src/main.cc | 2 +- .../visitor/translation_unit_visitor.cc | 2 + src/util/util.cc | 27 ++++++-- tests/CMakeLists.txt | 16 ++++- tests/t00018/t00018.h | 2 + tests/t30002/t30002.cc | 1 + thirdparty/glob/glob.hpp | 2 +- 16 files changed, 106 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd5d69a7..e2bb0f79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,11 @@ message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") message(STATUS "LLVM library dir: ${LLVM_LIBRARY_DIR}") +if(MSVC) + # LLVM_BUILD_LLVM_DYLIB is not available on Windows + set(LINK_LLVM_SHARED NO) +endif(MSVC) + if(LINK_LLVM_SHARED) set(LIBTOOLING_LIBS clang-cpp LLVM) else(LINK_LLVM_SHARED) @@ -59,6 +64,7 @@ else(LINK_LLVM_SHARED) clangDriver clangParse clangSema + clangSupport clangAnalysis clangAST clangBasic @@ -78,8 +84,19 @@ else(LINK_LLVM_SHARED) LLVMBitReader LLVMCore LLVMSupport) + if(MSVC) + list(APPEND LIBTOOLING_LIBS + LLVMWindowsDriver + LLVMWindowsManifest) + endif(MSVC) endif(LINK_LLVM_SHARED) +if("${LIBTOOLING_LIBS}" STREQUAL "") + message(FATAL_ERROR "Failed to find LibTooling libraries!") +else() + message(STATUS "Found LibTooling libraries: ${LIBTOOLING_LIBS}") +endif() + # # Setup threads library # @@ -90,22 +107,28 @@ find_package(Threads REQUIRED) # message(STATUS "Checking for yaml-cpp...") if(APPLE) -find_package(PkgConfig) -if(PKG_CONFIG_FOUND) - pkg_check_modules(YAML_CPP yaml-cpp) - find_path(YAML_CPP_INCLUDE_DIR - NAMES yaml.h - PATHS ${YAML_CPP_INCLUDE_DIR} /usr/local/include/yaml-cpp) - find_library(YAML_CPP_LIBRARY - NAMES yaml-cpp - PATHS ${YAML_CPP_LIBRARIES} /usr/local/lib) - set(YAML_CPP_LIBRARY_DIR /usr/local/lib) -endif() -else(APPLE) + find_package(PkgConfig) + if(PKG_CONFIG_FOUND) + pkg_check_modules(YAML_CPP yaml-cpp) + find_path(YAML_CPP_INCLUDE_DIR + NAMES yaml.h + PATHS ${YAML_CPP_INCLUDE_DIR} /usr/local/include/yaml-cpp) + find_library(YAML_CPP_LIBRARY + NAMES yaml-cpp + PATHS ${YAML_CPP_LIBRARIES} /usr/local/lib) + set(YAML_CPP_LIBRARY_DIR /usr/local/lib) + endif(PKG_CONFIG_FOUND) +elseif(MSVC) + set(YAML_CPP_LIBRARIES "yaml-cpp") +else() find_package(yaml-cpp REQUIRED) -endif(APPLE) +endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -std=c++17 -Wno-unused-parameter -Wno-unused-private-field") +if("${YAML_CPP_LIBRARIES}" STREQUAL "") + message(FATAL_ERROR "Failed to find yaml-cpp library!") +else() + message(STATUS "Found yaml-cpp libraries: ${YAML_CPP_LIBRARIES}") +endif() link_directories(${LLVM_LIBRARY_DIR} ${YAML_CPP_LIBRARY_DIR}) @@ -129,7 +152,13 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OUTPUT_VARIABLE GCC_STDDEF_INCLUDE) message(STATUS "FOUND GCC STDDEF INCLUDE ${GCC_STDDEF_INCLUDE}") include_directories(${GCC_STDDEF_INCLUDE}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -std=c++17 -Wno-unused-parameter -Wno-unused-private-field") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${GCC_STDDEF_INCLUDE}") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -std=c++17 -Wno-unused-parameter -Wno-unused-private-field") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLLVM_FORCE_USE_OLD_TOOLCHAIN /W1 /std:c++17 /bigobj /wd4291 /wd4624 /wd4244") + set(LINK_OPTIONS "${LINK_OPTIONS} /NODEFAULTLIB:MSVCRT /NODEFAULTLIB:MSVCRTD") endif() message(STATUS "Using CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") @@ -145,7 +174,6 @@ include_directories(${THIRDPARTY_HEADERS_DIR}) include_directories(${PROJECT_SOURCE_DIR}/src/) include_directories(${PROJECT_BINARY_DIR}/src/version) - # # Generate source list dynamically # @@ -153,19 +181,25 @@ file(GLOB_RECURSE SOURCES src/*.cc include/*.h) set(MAIN_SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc) list(REMOVE_ITEM SOURCES ${MAIN_SOURCE_FILE}) - # # Define library target for linking with test cases and output executable # -add_library(clang-umllib OBJECT ${SOURCES}) +if(MSVC) + add_library(clang-umllib STATIC ${SOURCES}) + set(MSVC_LIBRARIES "version") +else(MSVC) + add_library(clang-umllib OBJECT ${SOURCES}) +endif(MSVC) # # Define the target executable clang-uml # add_executable(clang-uml ${MAIN_SOURCE_FILE}) + target_link_libraries(clang-uml ${YAML_CPP_LIBRARIES} ${LIBTOOLING_LIBS} + ${MSVC_LIBRARIES} clang-umllib Threads::Threads) diff --git a/src/class_diagram/model/class_parent.h b/src/class_diagram/model/class_parent.h index 1e059097..79c872c9 100644 --- a/src/class_diagram/model/class_parent.h +++ b/src/class_diagram/model/class_parent.h @@ -32,8 +32,6 @@ public: clanguml::common::id_t id() const noexcept { return id_; } void set_id(clanguml::common::id_t id) { id_ = id; } - void set_id(id_t id); - void is_virtual(bool is_virtual); bool is_virtual() const; diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 4e9d8a6c..7206e50f 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -763,6 +763,7 @@ void translation_unit_visitor::process_class_children( // Static fields have to be processed by iterating over variable // declarations +#ifndef _MSC_VER for (const auto *decl : cls->decls()) { if (decl->getKind() == clang::Decl::Var) { const clang::VarDecl *variable_declaration{ @@ -788,7 +789,7 @@ void translation_unit_visitor::process_class_children( } } } - +#endif if (cls->isCompleteDefinition()) for (const auto *friend_declaration : cls->friends()) { if (friend_declaration != nullptr) @@ -1429,7 +1430,7 @@ std::unique_ptr translation_unit_visitor:: template_instantiation.set_name(template_decl->getNameAsString()); template_instantiation.set_namespace(ns); template_instantiation.set_id(template_decl->getID() + - static_cast( + static_cast( std::hash{}(full_template_specialization_name) >> 4U)); build_template_instantiation_process_template_arguments(parent, diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index f5b9ea76..8427fef3 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -191,14 +191,17 @@ inja::json generator::element_context(const E &e) const if (!e.file().empty()) { std::filesystem::path file{e.file()}; std::string relative_path = file.string(); - +#if _MSC_VER + if (file.is_absolute() && ctx.contains("git")) +#else if (file.is_absolute() && ctx.template contains("git")) +#endif relative_path = - std::filesystem::relative(file, ctx["git"]["toplevel"]); + std::filesystem::relative(file, ctx["git"]["toplevel"]).string(); ctx["element"]["source"]["path"] = relative_path; ctx["element"]["source"]["full_path"] = file.string(); - ctx["element"]["source"]["name"] = file.filename(); + ctx["element"]["source"]["name"] = file.filename().string(); ctx["element"]["source"]["line"] = e.line(); } diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index d11951f9..b65e12b4 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -184,12 +184,12 @@ tvl::value_t namespace_filter::match( auto namespace_starts_with_element_qualified_name = nsit.starts_with(e.get_namespace()); - auto result = element_full_name_starts_with_namespace | + auto result = element_full_name_starts_with_namespace || element_full_name_equals_pattern; if (is_inclusive) result = - result | namespace_starts_with_element_qualified_name; + result || namespace_starts_with_element_qualified_name; return result; }); diff --git a/src/common/model/source_file.h b/src/common/model/source_file.h index 7ce58e3b..dd171bfe 100644 --- a/src/common/model/source_file.h +++ b/src/common/model/source_file.h @@ -53,7 +53,7 @@ public: explicit source_file(const std::filesystem::path &p) { set_path({p.parent_path().string()}); - set_name(p.filename()); + set_name(p.filename().string()); is_absolute_ = p.is_absolute(); set_id(common::to_id(p)); } diff --git a/src/common/visitor/translation_unit_visitor.h b/src/common/visitor/translation_unit_visitor.h index 56f5a105..12671d31 100644 --- a/src/common/visitor/translation_unit_visitor.h +++ b/src/common/visitor/translation_unit_visitor.h @@ -103,7 +103,7 @@ protected: private: clang::SourceManager &source_manager_; - const clanguml::config::diagram &config_; + [[maybe_unused]] const clanguml::config::diagram &config_; std::unique_ptr comment_visitor_; }; diff --git a/src/decorators/decorators.cc b/src/decorators/decorators.cc index 8e062353..0b112e9d 100644 --- a/src/decorators/decorators.cc +++ b/src/decorators/decorators.cc @@ -62,7 +62,7 @@ decorator_toks decorator::tokenize(const std::string &label, std::string_view c) decorator_toks res; res.label = label; size_t pos{}; - const auto *it = c.begin(); + auto it = c.begin(); std::advance(it, label.size()); if (*it == ':') { diff --git a/src/include_diagram/visitor/translation_unit_visitor.h b/src/include_diagram/visitor/translation_unit_visitor.h index 7b4c21ea..b496636e 100644 --- a/src/include_diagram/visitor/translation_unit_visitor.h +++ b/src/include_diagram/visitor/translation_unit_visitor.h @@ -104,7 +104,7 @@ public: void finalize() { } private: - clang::SourceManager &source_manager_; + [[maybe_unused]] clang::SourceManager &source_manager_; // Reference to the output diagram model clanguml::include_diagram::model::diagram &diagram_; diff --git a/src/main.cc b/src/main.cc index da969ce9..2ee80fec 100644 --- a/src/main.cc +++ b/src/main.cc @@ -551,7 +551,7 @@ int add_config_diagram(clanguml::common::model::diagram_t type, return 1; } - YAML::Node doc = YAML::LoadFile(config_file); + YAML::Node doc = YAML::LoadFile(config_file.string()); for (YAML::const_iterator it = doc["diagrams"].begin(); it != doc["diagrams"].end(); ++it) { diff --git a/src/package_diagram/visitor/translation_unit_visitor.cc b/src/package_diagram/visitor/translation_unit_visitor.cc index 15e85d33..30349496 100644 --- a/src/package_diagram/visitor/translation_unit_visitor.cc +++ b/src/package_diagram/visitor/translation_unit_visitor.cc @@ -220,6 +220,7 @@ void translation_unit_visitor::process_class_children( // Static fields have to be processed by iterating over variable // declarations +#ifndef _MSC_VER for (const auto *decl : cls.decls()) { if (decl->getKind() == clang::Decl::Var) { const clang::VarDecl *variable_declaration{ @@ -230,6 +231,7 @@ void translation_unit_visitor::process_class_children( } } } +#endif if (cls.isCompleteDefinition()) for (const auto *friend_declaration : cls.friends()) { diff --git a/src/util/util.cc b/src/util/util.cc index 3849f544..10c5ea85 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -49,12 +49,16 @@ void setup_logging(int verbose) std::string get_process_output(const std::string &command) { constexpr size_t kBufferSize{1024}; - std::array buffer{}; std::string result; + +#if defined(__linux) || defined(__unix) std::unique_ptr pipe( popen(command.c_str(), "r"), pclose); - +#elif defined(WINDOWS) || defined(_WIN32) || defined(WIN32) + std::unique_ptr pipe( + _popen(command.c_str(), "r"), _pclose); +#endif if (!pipe) { throw std::runtime_error("popen() failed!"); } @@ -68,12 +72,25 @@ std::string get_process_output(const std::string &command) std::string get_env(const std::string &name) { +#if defined(__linux) || defined(__unix) const char *value = std::getenv(name.c_str()); // NOLINT if (value == nullptr) return {}; return std::string{value}; +#elif defined(WINDOWS) || defined(_WIN32) || defined(WIN32) + static constexpr auto kMaxEnvLength = 2096U; + static char value[kMaxEnvLength]; + const DWORD ret = + GetEnvironmentVariableA(name.c_str(), value, kMaxEnvLength); + if (ret == 0 || ret > kMaxEnvLength) + return {}; + else + return value; +#else + return {}; +#endif } bool is_git_repository() @@ -83,13 +100,9 @@ bool is_git_repository() if (!env.empty()) return true; -#if defined(_WIN32) || defined(_WIN64) - return false; -#else return contains( - trim(get_process_output("git rev-parse --git-dir 2> /dev/null")), + trim(get_process_output("git rev-parse --git-dir")), ".git"); -#endif } std::string get_git_branch() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8d6a31ac..19326ed0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,9 +4,15 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 17) -set(TEST_DISABLE_WARNINGS_DEBUG "-Wno-unused-parameter -Wno-unused-private-field -Wno-unused-variable -Wno-attributes -Wno-nonnull") -set(TEST_DISABLE_WARNINGS_RELEASE "${TEST_DISABLE_WARNINGS} -Wno-aggressive-loop-optimizations") - +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(TEST_DISABLE_WARNINGS_DEBUG "-Wno-unused-parameter -Wno-unused-private-field -Wno-unused-variable -Wno-attributes -Wno-nonnull") + set(TEST_DISABLE_WARNINGS_RELEASE "${TEST_DISABLE_WARNINGS} -Wno-aggressive-loop-optimizations") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(TEST_DISABLE_WARNINGS_DEBUG "-Wno-unused-parameter -Wno-unused-private-field -Wno-unused-variable -Wno-attributes -Wno-nonnull") + set(TEST_DISABLE_WARNINGS_RELEASE "${TEST_DISABLE_WARNINGS} -Wno-aggressive-loop-optimizations") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W1 /std:c++17 /bigobj /wd4624") +endif() set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} ${LIBCLANG_CXXFLAGS} ${TEST_DISABLE_WARNINGS_RELEASE}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} ${LIBCLANG_CXXFLAGS} ${TEST_DISABLE_WARNINGS_DEBUG}") @@ -28,6 +34,10 @@ set(CLANG_UML_TEST_LIBRARIES ${LIBTOOLING_LIBS} Threads::Threads) +if(MSVC) + list(APPEND CLANG_UML_TEST_LIBRARIES "Version.lib") +endif(MSVC) + set(CLANG_UML_TEST_UTIL_SRC test_util.cc ${TEST_UTIL_SOURCES}) set(CLANG_UML_TEST_UTIL_HEADER catch.h) diff --git a/tests/t00018/t00018.h b/tests/t00018/t00018.h index ca993d08..870f6316 100644 --- a/tests/t00018/t00018.h +++ b/tests/t00018/t00018.h @@ -1,6 +1,8 @@ #pragma once +#ifndef _MSC_VER #include +#endif #include #include diff --git a/tests/t30002/t30002.cc b/tests/t30002/t30002.cc index c5e55b77..a731d51f 100644 --- a/tests/t30002/t30002.cc +++ b/tests/t30002/t30002.cc @@ -2,6 +2,7 @@ #include #include #include +#include namespace clanguml { namespace t30002 { diff --git a/thirdparty/glob/glob.hpp b/thirdparty/glob/glob.hpp index 37322701..0df3f96e 100644 --- a/thirdparty/glob/glob.hpp +++ b/thirdparty/glob/glob.hpp @@ -177,7 +177,7 @@ static inline fs::path expand_tilde(fs::path path) #ifdef _WIN32 char *home; size_t sz; - errno_t err = _dupenv_s(&home, &sz, "USERPROFILE"); + [[maybe_unused]] errno_t err = _dupenv_s(&home, &sz, "USERPROFILE"); #else const char *home = std::getenv("HOME"); #endif From 1cbc3e697daa5cc6048fa0cc92dca2ab99cf283e Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Fri, 6 Jan 2023 23:55:27 +0000 Subject: [PATCH 02/11] Added installation documentation page --- docs/installation.md | 124 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 docs/installation.md diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..f11cbb6d --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,124 @@ +# Installation + +### Distribution packages + +#### Ubuntu + +```bash +# Currently supported Ubuntu versions are Focal, Jammy and Kinetic +sudo add-apt-repository ppa:bkryza/clang-uml +sudo apt update +sudo apt install clang-uml +``` + +#### Fedora + +```bash +# Fedora 36 +wget https://github.com/bkryza/clang-uml/releases/download/0.3.0/clang-uml-0.3.0-1.fc36.x86_64.rpm +sudo dnf install ./clang-uml-0.3.0-1.fc36.x86_64.rpm + +# Fedora 37 +wget https://github.com/bkryza/clang-uml/releases/download/0.3.0/clang-uml-0.3.0-1.fc37.x86_64.rpm +sudo dnf install ./clang-uml-0.3.0-1.fc37.x86_64.rpm +``` + +#### Conda + +```bash +conda config --add channels conda-forge +conda config --set channel_priority strict +conda install -c bkryza/label/clang-uml clang-uml +``` + +### Building from source + +First make sure that you have the following dependencies installed: + +```bash +# Ubuntu (clang version will vary depending on Ubuntu version) +apt install ccache cmake libyaml-cpp-dev clang-12 libclang-12-dev libclang-cpp12-dev + +# macos +brew install ccache cmake llvm yaml-cpp +``` + +Then proceed with building the sources: + +```bash +git clone https://github.com/bkryza/clang-uml +cd clang-uml +# Please note that top level Makefile is just a convenience wrapper for CMake +make release +release/clang-uml --help + +# To build using a specific installed version of LLVM use: +LLVM_VERSION=14 make release + +# Optionally +make install +# or +export PATH=$PATH:$PWD/release +``` + +#### macos +```bash +# On macos, it is necessary to build clang-uml using the same llvm against which it is linked, e.g. +brew install llvm + +export CC=/usr/local/opt/llvm/bin/clang +export CCX=/usr/local/opt/llvm/bin/clang++ +LLVM_VERSION=14 make release +``` + +#### Windows + +##### Visual Studio native build + +These steps present how to build and use `clang-uml` using Visual Studio only without any +`vcpkg` or `choco` dependencies package managers. + +First, install the following dependencies: + +* [Python 3](https://www.python.org/downloads/windows/) +* [Git](https://git-scm.com/download/win) +* [CMake](https://cmake.org/download/) +* [Visual Studio](https://visualstudio.microsoft.com/vs/community/) +* [Clang Power Tools](https://clangpowertools.com/) - this can be installed from VS Extension manager + +Create installation directory for `clang-uml` and its dependencies: +```bash +# This is where our working clang-uml binary will be located +mkdir C:\clang-uml +# This directory will be removed after build +mkdir C:\clang-uml-tmp +cd C:\clang-uml-tmp +``` + +Build and install yaml-cpp: + +```bash +git clone https://github.com/jbeder/yaml-cpp +cd yaml-cpp +git checkout yaml-cpp-0.7.0 +cd .. +cmake -S .\yaml-cpp\ -B .\yaml-cpp-build\ -DCMAKE_INSTALL_PREFIX="C:\clang-uml" -Thost=x64 +cd yaml-cpp-build +msbuild .\INSTALL.sln -maxcpucount /p:Configuration=Release +``` + +Build and install LLVM: + +```bash +pip install psutil +git clone --branch llvmorg-15.0.6 --depth 1 https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-15.0.6.zip +cmake -S .\llvm\llvm -B llvm-build -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_INSTALL_PREFIX="C:\clang-uml" -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=X86 -Thost=x64 +msbuild .\INSTALL.sln -maxcpucount /p:Configuration=Release +``` + +Build and install clang-uml: + +```bash +git clone https://github.com/bkryza/clang-uml +cmake -S .\clang-uml\ -B .\clang-uml-build\ -DCMAKE_PREFIX_PATH="C:\clang-uml" -Thost=x64 +``` From f1f6051cf79aa8dc1d69b94c96a4286ba8a16849 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 11:07:00 +0000 Subject: [PATCH 03/11] Fixed path filters on Windows --- src/common/model/diagram_filter.cc | 4 +++- src/common/model/source_file.h | 6 +++++- src/config/config.cc | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index b65e12b4..bac06e6b 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -391,8 +391,10 @@ tvl::value_t paths_filter::match( auto pp = p.fs_path(root_); for (const auto &path : paths_) { - if (util::starts_with(pp, path)) + if (pp.root_name().string() == path.root_name().string() && + util::starts_with(pp, path)) { return true; + } } return false; diff --git a/src/common/model/source_file.h b/src/common/model/source_file.h index dd171bfe..108e29ec 100644 --- a/src/common/model/source_file.h +++ b/src/common/model/source_file.h @@ -37,7 +37,11 @@ namespace clanguml::common::model { enum class source_file_t { kDirectory, kHeader, kImplementation }; struct fs_path_sep { +#ifdef _WIN32 + static constexpr std::string_view value = "\\"; +#else static constexpr std::string_view value = "/"; +#endif }; using filesystem_path = common::model::path; @@ -107,7 +111,7 @@ public: res /= name(); if (is_absolute_) - res = "/" / res; + res = fs_path_sep::value / res; else res = base / res; diff --git a/src/config/config.cc b/src/config/config.cc index d6061fb6..1db24d1c 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -599,7 +599,7 @@ template <> struct convert { // Ensure relative_to has a value if (!rhs.relative_to.has_value) - rhs.relative_to.set(std::filesystem::current_path()); + rhs.relative_to.set(std::filesystem::current_path().lexically_normal()); rhs.initialize_type_aliases(); From a1a9d4ae9996fbc44db975461f25fe214cc46961 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 12:32:46 +0100 Subject: [PATCH 04/11] Fixed formatting --- src/common/generators/plantuml/generator.h | 3 ++- src/config/config.cc | 3 ++- src/util/util.cc | 3 +-- tests/t30002/t30002.cc | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 8427fef3..19114727 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -197,7 +197,8 @@ inja::json generator::element_context(const E &e) const if (file.is_absolute() && ctx.template contains("git")) #endif relative_path = - std::filesystem::relative(file, ctx["git"]["toplevel"]).string(); + std::filesystem::relative(file, ctx["git"]["toplevel"]) + .string(); ctx["element"]["source"]["path"] = relative_path; ctx["element"]["source"]["full_path"] = file.string(); diff --git a/src/config/config.cc b/src/config/config.cc index 1db24d1c..36e56d5d 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -599,7 +599,8 @@ template <> struct convert { // Ensure relative_to has a value if (!rhs.relative_to.has_value) - rhs.relative_to.set(std::filesystem::current_path().lexically_normal()); + rhs.relative_to.set( + std::filesystem::current_path().lexically_normal()); rhs.initialize_type_aliases(); diff --git a/src/util/util.cc b/src/util/util.cc index 10c5ea85..9579002d 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -101,8 +101,7 @@ bool is_git_repository() return true; return contains( - trim(get_process_output("git rev-parse --git-dir")), - ".git"); + trim(get_process_output("git rev-parse --git-dir")), ".git"); } std::string get_git_branch() diff --git a/tests/t30002/t30002.cc b/tests/t30002/t30002.cc index a731d51f..159b6d41 100644 --- a/tests/t30002/t30002.cc +++ b/tests/t30002/t30002.cc @@ -1,8 +1,8 @@ #include #include #include -#include #include +#include namespace clanguml { namespace t30002 { From 0ace02398589e4e79d22755d1e6776fedb3e38a8 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 14:41:26 +0100 Subject: [PATCH 05/11] Fixed building on macos --- Makefile | 10 +++++++++- src/common/visitor/translation_unit_visitor.cc | 1 - src/common/visitor/translation_unit_visitor.h | 2 -- .../visitor/translation_unit_visitor.cc | 6 +++--- src/include_diagram/visitor/translation_unit_visitor.h | 2 -- src/util/util.cc | 5 +++-- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 72c0ce4d..d9088428 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,15 @@ .DEFAULT_GOAL := debug -NUMPROC ?= $(shell nproc) +OS_UNAME := $(shell uname -s) + +ifeq ($(OS_UNAME),Linux) + NUMPROC ?= $(shell nproc) +else ifeq ($(OS_UNAME),Darwin) + NUMPROC ?= $(shell sysctl -n hw.logicalcpu) +else + NUMPROC ?= 1 +endif LLVM_VERSION ?= CMAKE_CXX_FLAGS ?= diff --git a/src/common/visitor/translation_unit_visitor.cc b/src/common/visitor/translation_unit_visitor.cc index bd3a6071..bfbb178b 100644 --- a/src/common/visitor/translation_unit_visitor.cc +++ b/src/common/visitor/translation_unit_visitor.cc @@ -26,7 +26,6 @@ namespace clanguml::common::visitor { translation_unit_visitor::translation_unit_visitor( clang::SourceManager &sm, const clanguml::config::diagram &config) : source_manager_{sm} - , config_{config} { if (config.comment_parser() == config::comment_parser_t::plain) { comment_visitor_ = diff --git a/src/common/visitor/translation_unit_visitor.h b/src/common/visitor/translation_unit_visitor.h index 12671d31..e4712597 100644 --- a/src/common/visitor/translation_unit_visitor.h +++ b/src/common/visitor/translation_unit_visitor.h @@ -103,8 +103,6 @@ protected: private: clang::SourceManager &source_manager_; - [[maybe_unused]] const clanguml::config::diagram &config_; - std::unique_ptr comment_visitor_; }; } // namespace clanguml::common::visitor diff --git a/src/include_diagram/visitor/translation_unit_visitor.cc b/src/include_diagram/visitor/translation_unit_visitor.cc index 739ae473..a2ebd18b 100644 --- a/src/include_diagram/visitor/translation_unit_visitor.cc +++ b/src/include_diagram/visitor/translation_unit_visitor.cc @@ -24,11 +24,11 @@ namespace clanguml::include_diagram::visitor { -translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm, +translation_unit_visitor::translation_unit_visitor( + clang::SourceManager & /*sm*/, clanguml::include_diagram::model::diagram &diagram, const clanguml::config::include_diagram &config) - : source_manager_{sm} - , diagram_{diagram} + : diagram_{diagram} , config_{config} { } diff --git a/src/include_diagram/visitor/translation_unit_visitor.h b/src/include_diagram/visitor/translation_unit_visitor.h index b496636e..54cc2081 100644 --- a/src/include_diagram/visitor/translation_unit_visitor.h +++ b/src/include_diagram/visitor/translation_unit_visitor.h @@ -104,8 +104,6 @@ public: void finalize() { } private: - [[maybe_unused]] clang::SourceManager &source_manager_; - // Reference to the output diagram model clanguml::include_diagram::model::diagram &diagram_; diff --git a/src/util/util.cc b/src/util/util.cc index 9579002d..45bb3ec7 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -52,13 +52,14 @@ std::string get_process_output(const std::string &command) std::array buffer{}; std::string result; -#if defined(__linux) || defined(__unix) +#if defined(__linux) || defined(__unix) || defined(__APPLE__) std::unique_ptr pipe( popen(command.c_str(), "r"), pclose); -#elif defined(WINDOWS) || defined(_WIN32) || defined(WIN32) +#elif defined(_WIN32) std::unique_ptr pipe( _popen(command.c_str(), "r"), _pclose); #endif + if (!pipe) { throw std::runtime_error("popen() failed!"); } From f1bae8289e447c8c902740fd771d5b1f3d9d7a91 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 15:34:50 +0000 Subject: [PATCH 06/11] Moved installation instructions to separate doc page --- README.md | 66 +------------------------------------------- docs/installation.md | 14 ++++------ 2 files changed, 7 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 0eb6110c..9438789f 100644 --- a/README.md +++ b/README.md @@ -46,71 +46,7 @@ More comprehensive documentation can be found [here](./docs/README.md). ## Installation -### Distribution packages - -#### Ubuntu - -```bash -# Currently supported Ubuntu versions are Focal, Jammy and Kinetic -sudo add-apt-repository ppa:bkryza/clang-uml -sudo apt update -sudo apt install clang-uml -``` - -#### Fedora - -```bash -# Fedora 36 -wget https://github.com/bkryza/clang-uml/releases/download/0.3.0/clang-uml-0.3.0-1.fc36.x86_64.rpm -sudo dnf install ./clang-uml-0.3.0-1.fc36.x86_64.rpm - -# Fedora 37 -wget https://github.com/bkryza/clang-uml/releases/download/0.3.0/clang-uml-0.3.0-1.fc37.x86_64.rpm -sudo dnf install ./clang-uml-0.3.0-1.fc37.x86_64.rpm -``` - -#### Conda - -```bash -conda config --add channels conda-forge -conda config --set channel_priority strict -conda install -c bkryza/label/clang-uml clang-uml -``` - -### Building from source - -First make sure that you have the following dependencies installed: - -```bash -# Ubuntu (clang version will vary depending on Ubuntu version) -apt install ccache cmake libyaml-cpp-dev clang-12 libclang-12-dev libclang-cpp12-dev - -# macos -brew install ccache cmake llvm yaml-cpp -``` - -Then proceed with building the sources: - -```bash -git clone https://github.com/bkryza/clang-uml -cd clang-uml -# Please note that top level Makefile is just a convenience wrapper for CMake -make release -release/clang-uml --help - -# To build using a specific installed version of LLVM use: -LLVM_VERSION=14 make release - -# Optionally -make install -# or -export PATH=$PATH:$PWD/release - -# On macos, it is necessary to build clang-uml using the same llvm against which it is linked, e.g. -export CC=/usr/local/opt/llvm/bin/clang -export CCX=/usr/local/opt/llvm/bin/clang++ -LLVM_VERSION=14 make release -``` +Installation instruction for `Linux`, `macos` and `Windows` can be found [here](./docs/installation.md). ## Usage diff --git a/docs/installation.md b/docs/installation.md index f11cbb6d..57ccd870 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -33,14 +33,12 @@ conda install -c bkryza/label/clang-uml clang-uml ### Building from source +#### Linux First make sure that you have the following dependencies installed: ```bash # Ubuntu (clang version will vary depending on Ubuntu version) apt install ccache cmake libyaml-cpp-dev clang-12 libclang-12-dev libclang-cpp12-dev - -# macos -brew install ccache cmake llvm yaml-cpp ``` Then proceed with building the sources: @@ -62,9 +60,9 @@ export PATH=$PATH:$PWD/release ``` #### macos + ```bash -# On macos, it is necessary to build clang-uml using the same llvm against which it is linked, e.g. -brew install llvm +brew install ccache cmake llvm yaml-cpp export CC=/usr/local/opt/llvm/bin/clang export CCX=/usr/local/opt/llvm/bin/clang++ @@ -75,10 +73,9 @@ LLVM_VERSION=14 make release ##### Visual Studio native build -These steps present how to build and use `clang-uml` using Visual Studio only without any -`vcpkg` or `choco` dependencies package managers. +These steps present how to build and use `clang-uml` natively using Visual Studio only. -First, install the following dependencies: +First, install the following dependencies manually: * [Python 3](https://www.python.org/downloads/windows/) * [Git](https://git-scm.com/download/win) @@ -89,6 +86,7 @@ First, install the following dependencies: Create installation directory for `clang-uml` and its dependencies: ```bash # This is where our working clang-uml binary will be located +# If you change this path, adapt all consecutive steps mkdir C:\clang-uml # This directory will be removed after build mkdir C:\clang-uml-tmp From d64f974348e07ebcbb398ff9047f0e0c3022aea8 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 17:48:27 +0000 Subject: [PATCH 07/11] Updated README --- CHANGELOG.md | 2 ++ README.md | 1 + docs/installation.md | 34 +++++++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c8aeaa5..b93cf941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # CHANGELOG + * Added support for building with Microsoft Visual Studio + ### 0.3.0 * Added support for sequence diagrams with template code diff --git a/README.md b/README.md index 9438789f..fa7372d1 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Nowadays, this file can be generated rather easily using multiple methods: * For Boost-based projects try [commands_to_compilation_database](https://github.com/tee3/commands_to_compilation_database) * For SCons, invoke `compilation_db` tool (requires SCons > 4.0.0) +* For Microsoft Visual Studio projects try [Clang Power Tools](https://www.clangpowertools.com) ### Invocation diff --git a/docs/installation.md b/docs/installation.md index 57ccd870..56acca9a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -81,11 +81,13 @@ First, install the following dependencies manually: * [Git](https://git-scm.com/download/win) * [CMake](https://cmake.org/download/) * [Visual Studio](https://visualstudio.microsoft.com/vs/community/) -* [Clang Power Tools](https://clangpowertools.com/) - this can be installed from VS Extension manager + +> All the following steps should be invoked in `Developer PowerShell for VS`. Create installation directory for `clang-uml` and its dependencies: + ```bash -# This is where our working clang-uml binary will be located +# This is where clang-uml binary and its dependencies will be installed after build # If you change this path, adapt all consecutive steps mkdir C:\clang-uml # This directory will be removed after build @@ -93,7 +95,7 @@ mkdir C:\clang-uml-tmp cd C:\clang-uml-tmp ``` -Build and install yaml-cpp: +Build and install `yaml-cpp`: ```bash git clone https://github.com/jbeder/yaml-cpp @@ -105,18 +107,36 @@ cd yaml-cpp-build msbuild .\INSTALL.sln -maxcpucount /p:Configuration=Release ``` -Build and install LLVM: +Build and install `LLVM`: ```bash pip install psutil -git clone --branch llvmorg-15.0.6 --depth 1 https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-15.0.6.zip +# Update the LLVM branch if necessary +git clone --branch llvmorg-15.0.6 --depth 1 https://github.com/llvm/llvm-project.git llvm cmake -S .\llvm\llvm -B llvm-build -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_INSTALL_PREFIX="C:\clang-uml" -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=X86 -Thost=x64 -msbuild .\INSTALL.sln -maxcpucount /p:Configuration=Release +cd llvm-build +msbuild .\INSTALL.sln -maxcpucount /p:Configuration=Release ``` -Build and install clang-uml: +Build and install `clang-uml`: ```bash git clone https://github.com/bkryza/clang-uml cmake -S .\clang-uml\ -B .\clang-uml-build\ -DCMAKE_PREFIX_PATH="C:\clang-uml" -Thost=x64 +cd clang-uml-build +msbuild .\INSTALL.sln -maxcpucount /p:Configuration=Release +``` + +Check if `clang-uml` works: + +```bash +cd C:\clang-uml +bin\clang-uml.exe --version +``` +It should produce something like: +```bash +clang-uml 0.3.0 +Copyright (C) 2021-2023 Bartek Kryza +Built against LLVM/Clang libraries version: 15.0.6 +Using LLVM/Clang libraries version: clang version 15.0.6 (https://github.com/llvm/llvm-project.git 088f33605d8a61ff519c580a71b1dd57d16a03f8) ``` From a35eec202365f0f591062cb6bbd66d3e225adb32 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 19:08:45 +0000 Subject: [PATCH 08/11] Updated windows build instructions --- docs/installation.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 56acca9a..ad76475d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -122,7 +122,7 @@ Build and install `clang-uml`: ```bash git clone https://github.com/bkryza/clang-uml -cmake -S .\clang-uml\ -B .\clang-uml-build\ -DCMAKE_PREFIX_PATH="C:\clang-uml" -Thost=x64 +cmake -S .\clang-uml\ -B .\clang-uml-build\ -DCMAKE_INSTALL_PREFIX="C:\clang-uml" -DCMAKE_PREFIX_PATH="C:\clang-uml" -DBUILD_TESTS=OFF -Thost=x64 cd clang-uml-build msbuild .\INSTALL.sln -maxcpucount /p:Configuration=Release ``` @@ -140,3 +140,9 @@ Copyright (C) 2021-2023 Bartek Kryza Built against LLVM/Clang libraries version: 15.0.6 Using LLVM/Clang libraries version: clang version 15.0.6 (https://github.com/llvm/llvm-project.git 088f33605d8a61ff519c580a71b1dd57d16a03f8) ``` + +Finally, remove the temporary build directory: + +```bash +rm -r C:\clang-uml-tmp +``` \ No newline at end of file From d1ccee9c982745e3b98697d31ed73507c8a40da1 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 19:13:02 +0000 Subject: [PATCH 09/11] Fix handling of --compile-database option (Fixes #70) --- src/main.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.cc b/src/main.cc index 2ee80fec..4c257570 100644 --- a/src/main.cc +++ b/src/main.cc @@ -151,7 +151,7 @@ int main(int argc, const char *argv[]) CLI::App app{"Clang-based PlantUML diagram generator for C++"}; std::string config_path{".clang-uml"}; - std::string compilation_database_dir{'.'}; + std::string compilation_database_dir{}; std::vector diagram_names{}; std::optional output_directory; unsigned int thread_count{0}; @@ -245,6 +245,10 @@ int main(int argc, const char *argv[]) LOG_INFO("Loaded clang-uml config from {}", config_path); + if(!compilation_database_dir.empty()) { + config.compilation_database_dir.set(compilation_database_dir); + } + LOG_INFO("Loading compilation database from {} directory", config.compilation_database_dir()); From e0012cca8993141cd40781d7d987aae3b4e6dff5 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 19:16:35 +0000 Subject: [PATCH 10/11] Fixed formatting --- src/main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cc b/src/main.cc index 4c257570..eca1773d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -245,7 +245,7 @@ int main(int argc, const char *argv[]) LOG_INFO("Loaded clang-uml config from {}", config_path); - if(!compilation_database_dir.empty()) { + if (!compilation_database_dir.empty()) { config.compilation_database_dir.set(compilation_database_dir); } From 0fb0151feb81addf8d1c45f2a98982501f030e97 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 7 Jan 2023 19:24:22 +0000 Subject: [PATCH 11/11] Updated README --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fa7372d1..12209542 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ YAML configuration files. The main idea behind the project is to easily maintain up-to-date diagrams within a code-base or document legacy code. The configuration file or files for `clang-uml` define the type and contents of each generated diagram. -Currently the diagrams are generated in [PlantUML](https://plantuml.com) format. +Currently, the diagrams are generated in [PlantUML](https://plantuml.com) format. `clang-uml` currently supports C++ up to version 17. @@ -46,7 +46,7 @@ More comprehensive documentation can be found [here](./docs/README.md). ## Installation -Installation instruction for `Linux`, `macos` and `Windows` can be found [here](./docs/installation.md). +Installation instructions for `Linux`, `macos` and `Windows` can be found [here](./docs/installation.md). ## Usage @@ -403,6 +403,8 @@ exclude: - clanguml::common::ClassF ``` +More details on this can be found in the [diagram filters](./docs/diagram_filters.md) documentation section. + ### Test cases The build-in test cases used for unit testing of the `clang-uml`, can be browsed [here](./docs/test_cases.md). @@ -420,7 +422,7 @@ This project relies on the following great tools: ## Contributing -If you would like to contribute to the project, please checkout [contributing guidelines](./CONTRIBUTING.md). +If you would like to contribute to the project, please check out [contributing guidelines](./CONTRIBUTING.md). ## LICENSE