diff --git a/.gitignore b/.gitignore index 25b55aa4..26a06f93 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,8 @@ docs/diagrams coverage*.info +packaging/_BUILD +packaging/conda/meta.yaml # CLion diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..e563e6ef --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# CHANGELOG + +### 0.1.0 + * Initial release \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b9f1ee78..7eb2b75d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.12) project(clang-uml) @@ -6,7 +6,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}) +set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") @@ -17,12 +17,17 @@ set(UML_HEADERS_DIR ${PROJECT_SOURCE_DIR}/src/uml) option(LLVM_CONFIG_PATH "Path to custom llvm-config executable") +option(GIT_VERSION "clang-uml version" "0.1.0") + if(LLVM_CONFIG_PATH) message(STATUS "Using llvm-config from ${LLVM_CONFIG_PATH}") set(LIBCLANG_LLVM_CONFIG_EXECUTABLE ${LLVM_CONFIG_PATH}) set(LLVM_CONFIG_BINARY ${LLVM_CONFIG_PATH}) endif(LLVM_CONFIG_PATH) +#set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + message(STATUS "Checking for yaml-cpp...") find_package(yaml-cpp REQUIRED) @@ -45,6 +50,10 @@ find_package(LLVM REQUIRED CONFIG) set(CLANG_INCLUDE_DIRS "llvm/clang/include") set(CLANG_LIBS clang) +# Configure executable version +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/src/version) +configure_file(src/version.h.in ${PROJECT_BINARY_DIR}/src/version/version.h) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") execute_process(COMMAND gcc --print-file-name=include OUTPUT_STRIP_TRAILING_WHITESPACE @@ -61,6 +70,8 @@ include_directories(${THIRDPARTY_HEADERS_DIR}/cppast/include) include_directories(${THIRDPARTY_HEADERS_DIR}/cppast/external/type_safe/include) include_directories(${THIRDPARTY_HEADERS_DIR}/cppast/external/type_safe/external/debug_assert) include_directories(${PROJECT_SOURCE_DIR}/src/) +include_directories(${PROJECT_BINARY_DIR}/src/version) + file(GLOB_RECURSE SOURCES src/*.cc include/*.h) set(MAIN_SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc) @@ -69,16 +80,15 @@ list(REMOVE_ITEM SOURCES ${MAIN_SOURCE_FILE}) add_library(clang-umllib OBJECT ${SOURCES}) add_executable(clang-uml ${MAIN_SOURCE_FILE}) -install(TARGETS clang-uml DESTINATION ${CLANG_UML_INSTALL_BIN_DIR}) -target_link_libraries(clang-uml ${LIBCLANG_LIBRARIES} ${YAML_CPP_LIBRARIES} cppast clang-umllib) +target_link_libraries(clang-uml ${LIBCLANG_LIBRARIES} ${YAML_CPP_LIBRARIES} cppast clang-umllib Threads::Threads) target_compile_features(clang-uml PRIVATE cxx_std_17) -install( - FILES - # add include after DESTINATION, then it works - DESTINATION include ${CMAKE_INSTALL_INCLUDEDIR} -) +include(GNUInstallDirs) + +install(TARGETS clang-uml DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(FILES LICENSE.md DESTINATION ${CMAKE_INSTALL_DOCDIR}) +install(FILES README.md DESTINATION ${CMAKE_INSTALL_DOCDIR}) # Enable testing via CTest enable_testing() diff --git a/Makefile b/Makefile index 6aaeb204..37a42714 100644 --- a/Makefile +++ b/Makefile @@ -26,12 +26,15 @@ LLVM_CONFIG_PATH ?= CMAKE_CXX_FLAGS ?= CMAKE_EXE_LINKER_FLAGS ?= +GIT_VERSION ?= $(shell git describe --tags --always --abbrev=7) + .PHONY: clean clean: rm -rf debug release debug/CMakeLists.txt: cmake -S . -B debug \ + -DGIT_VERSION=$(GIT_VERSION) \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS)" \ @@ -40,6 +43,7 @@ debug/CMakeLists.txt: release/CMakeLists.txt: cmake -S . -B release \ + -DGIT_VERSION=$(GIT_VERSION) \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS)" \ diff --git a/README.md b/README.md index 2cc2b802..ce9a1c15 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build status](https://github.com/bkryza/clang-uml/actions/workflows/build.yml/badge.svg)](https://github.com/bkryza/clang-uml/actions) [![Coverage](https://codecov.io/gh/bkryza/clang-uml/branch/master/graph/badge.svg)](https://codecov.io/gh/bkryza/clang-uml) +[![Version](https://img.shields.io/badge/version-0.1.0-blue)](https://github.com/bkryza/clang-uml/releases) `clang-uml` is an automatic C++ to [PlantUML](https://plantuml.com) class, sequence and package diagram generator, driven by YAML configuration files. The main idea behind the @@ -34,17 +35,34 @@ To see what `clang-uml` can do so far, checkout the diagrams generated for unit ## Installation +### Distribution packages + +#### Ubuntu +```bash +sudo add-apt-repository ppa:bkryza/clang-uml +sudo apt update +sudo apt install clang-uml +``` + +#### 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 -Currently, the only method to install `clang-uml` is from source. First make sure -that you have the following dependencies installed: +First make sure that you have the following dependencies installed: ```bash -# Ubuntu +# 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 ``` +> Please note that on macos this tool is not fully functional, i.e. several test cases fail. The build instructions are +> provided for development purposes only. Then proceed with building the sources: diff --git a/cmake/FindLibClang.cmake b/cmake/FindLibClang.cmake index 20d6e153..5299afe9 100644 --- a/cmake/FindLibClang.cmake +++ b/cmake/FindLibClang.cmake @@ -57,7 +57,7 @@ if (NOT LIBCLANG_LLVM_CONFIG_EXECUTABLE) find_program(LIBCLANG_LLVM_CONFIG_EXECUTABLE NAMES llvm-config PATHS "${BREW_LLVM_PATH}/bin") else () set(llvm_config_names llvm-config) - foreach(major RANGE 13 3) + foreach(major RANGE 15 3) list(APPEND llvm_config_names "llvm-config${major}" "llvm-config-${major}") foreach(minor RANGE 9 0) list(APPEND llvm_config_names "llvm-config${major}${minor}" "llvm-config-${major}.${minor}" "llvm-config-mp-${major}.${minor}") diff --git a/packaging/Makefile b/packaging/Makefile new file mode 100644 index 00000000..a59d6c91 --- /dev/null +++ b/packaging/Makefile @@ -0,0 +1,105 @@ +# Makefile +# +# Copyright (c) 2021-2022 Bartek Kryza +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SHELL := /bin/bash +.ONESHELL: + +.PHONY: download deb clean conda + +NAME ?= clang-uml +REBUILD ?= 1 +MAINTAINER_NAME ?= Bartek Kryza +MAINTAINER_EMAIL ?= bkryza@gmail.com +GPG_KEY ?= 702014E322FE5CA9B5D920F66CDA4566635E93B1 +OS ?= ubuntu +DIST ?= focal +TAR_EXT ?= gz + +build_dir = _BUILD/$(OS)/$(DIST) + +VERSION ?= $(shell git describe --tags --always --abbrev=7) +COMMIT ?= $(shell git rev-parse HEAD) +BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) +SOURCE_ARCHIVE ?= $(NAME)-$(VERSION).tar.$(TAR_EXT) +CONDA_TOKEN ?= + +# +# Replace mustache template variable in all files in directory recursively, +# e.g.: +# $(call subst_template,VERSION,${VERSION},debian) +# +define subst_template_dir + find $(3) -type f -exec sed -i "s/{{$(1)}}/$(2)/g" {} \; +endef + +define subst_conda_meta_yaml + find $(3) -name meta.yaml -exec sed -i "s/{{$(1)}}/$(2)/g" {} \; +endef + + + +_BUILD/$(SOURCE_ARCHIVE): + echo "############################" + echo "Creating source archive from latest commit $(COMMIT) - $(SOURCE_ARCHIVE)" + echo "############################" + mkdir -p $(build_dir) + git-archive-all --prefix=$(NAME)-$(VERSION)/ _BUILD/$(SOURCE_ARCHIVE) + +deb: _BUILD/$(SOURCE_ARCHIVE) + echo "############################" + echo "Creating deb source package for $(OS) $(DIST)" + echo "Creating directory: ", $(build_dir)/$(NAME)-$(VERSION) + echo "Extracting source archive..." + echo "############################" + rm -rf $(build_dir) + mkdir -p $(build_dir) + cp _BUILD/$(SOURCE_ARCHIVE) $(build_dir) + cd $(build_dir) + mkdir -p $(NAME)-$(VERSION) + tar xf $(SOURCE_ARCHIVE) -C $(NAME)-$(VERSION) --strip-components 1 + cp -R ../../../debian $(NAME)-$(VERSION)/debian + cd $(NAME)-$(VERSION) + $(call subst_template_dir,DATETIME,$(shell date -R),debian) + $(call subst_template_dir,OS,${OS},debian) + $(call subst_template_dir,NAME,${NAME},debian) + $(call subst_template_dir,VERSION,${VERSION},debian) + $(call subst_template_dir,REBUILD,${REBUILD},debian) + $(call subst_template_dir,DISTRIBUTION,${DIST},debian) + $(call subst_template_dir,MAINTAINER_NAME,${MAINTAINER_NAME},debian) + $(call subst_template_dir,MAINTAINER_EMAIL,${MAINTAINER_EMAIL},debian) + $(call subst_template_dir,GIT_COMMIT,${COMMIT},debian) + $(call subst_template_dir,GIT_BRANCH,${BRANCH},debian) + mk-origtargz ../$(NAME)-$(VERSION).tar.$(TAR_EXT) + cp debian/control.$(DIST) debian/control + # BUILD SOURCE PACKAGE FOR LAUNCHPAD + debuild -S -sa -us -d -k$(GPG_KEY) + # BUILD LOCALLY BINARY PACKAGE + # debuild -us -uc + +conda: _BUILD/$(SOURCE_ARCHIVE) + echo "############################" + echo "Creating conda archive from source file $(SOURCE_ARCHIVE)" + echo "############################" + conda config --add channels conda-forge + conda config --set channel_priority strict + mkdir -p _BUILD/conda + cp _BUILD/$(SOURCE_ARCHIVE) _BUILD/conda/ + cp conda/meta.yaml.in conda/meta.yaml + $(call subst_conda_meta_yaml,PKG_VERSION,${VERSION},conda) + $(call subst_conda_meta_yaml,PKG_SOURCE,..\/_BUILD\/clang-uml-$(VERSION).tar.$(TAR_EXT),conda) + $(call subst_conda_meta_yaml,GIT_COMMIT,${COMMIT},conda) + $(call subst_conda_meta_yaml,GIT_BRANCH,${BRANCH},conda) + conda build --user bkryza --token $(CONDA_TOKEN) conda diff --git a/packaging/README.md b/packaging/README.md new file mode 100644 index 00000000..12da4597 --- /dev/null +++ b/packaging/README.md @@ -0,0 +1,28 @@ +# Building releases + +* Update CHANGELOG.md +* Tag the release commit, e.g. ```git tag 0.1.0``` + +## Ubuntu + +```bash +cd packaging +make DIST=focal deb +make DIST=jammy deb + +cd _BUILD/ubuntu/focal +dput ppa:bkryza/clang-uml *.changes + +cd _BUILD/ubuntu/jammy +dput ppa:bkryza/clang-uml *.changes + +``` + +## Anaconda + +```bash +docker run --rm -v $PWD:$PWD continuum/miniconda3 bash +conda install conda-build +cd packaging +make conda +``` \ No newline at end of file diff --git a/packaging/conda/build.sh b/packaging/conda/build.sh new file mode 100644 index 00000000..3819ba95 --- /dev/null +++ b/packaging/conda/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +mkdir build && cd build + +export PKG_CONFIG_PATH="$BUILD_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH" + +export CLANGUML_GIT_TOPLEVEL_DIR=${SRC_DIR} + +cmake -DCMAKE_BUILD_TYPE=Release \ + -DGIT_VERSION=${GIT_VERSION} \ + -DCODE_COVERAGE=OFF \ + -DWITH_TESTS=ON \ + -DLLVM_CONFIG_PATH=${BUILD_PREFIX}/bin/llvm-config \ + -DCONDA_BUILD_PREFIX=${BUILD_PREFIX} \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + -DCMAKE_EXE_LINKER_FLAGS="-lyaml-cpp" \ + .. + +CTEST_OUTPUT_ON_FAILURE=1 make -j${CPU_COUNT} + +CTEST_OUTPUT_ON_FAILURE=1 ctest -j${CPU_COUNT} + +make install \ No newline at end of file diff --git a/packaging/conda/meta.yaml.in b/packaging/conda/meta.yaml.in new file mode 100644 index 00000000..4c890470 --- /dev/null +++ b/packaging/conda/meta.yaml.in @@ -0,0 +1,46 @@ +{% set name = "clang-uml" %} +{% set version = "{{PKG_VERSION}}" %} + +package: + name: {{ name|lower }} + version: {{ version|replace('-', '.') }} + +source: + url: "{{PKG_SOURCE}}" + +build: + binary_relocation: true + script_env: + - PKG_VERSION + - GIT_VERSION={{PKG_VERSION}} + - CLANGUML_GIT_REVISION={{PKG_VERSION}} + - CLANGUML_GIT_BRANCH={{GIT_BRANCH}} + - CLANGUML_GIT_COMMIT={{GIT_COMMIT}} + +requirements: + build: + - {{ compiler('c') }} + - {{ compiler('cxx') }} + - conda-forge::pkg-config + - conda-forge::yaml-cpp 0.7.0 + - conda-forge::clangdev 14.0.4 + - conda-forge::libclang 14.0.4 + - conda-forge::cmake + - conda-forge::git + - conda-forge::make # [unix] + run: + - conda-forge::yaml-cpp 0.7.0 + - conda-forge::libclang 14.0.4 + +test: + commands: + - $PREFIX/bin/clang-uml --version + +about: + home: https://github.com/bkryza/clang-uml + license: Apache 2.0 + summary: clang-uml is an automatic C++ UML diagram generator based on Clang. + +extra: + recipe-maintainers: + - bkryza \ No newline at end of file diff --git a/packaging/debian/changelog b/packaging/debian/changelog new file mode 100644 index 00000000..0112d0ac --- /dev/null +++ b/packaging/debian/changelog @@ -0,0 +1,5 @@ +clang-uml ({{VERSION}}-0{{OS}}{{REBUILD}}ppa1~{{DISTRIBUTION}}) {{DISTRIBUTION}}; urgency=low + + * Initial release + + -- Bartek Kryza {{DATETIME}} diff --git a/packaging/debian/compat b/packaging/debian/compat new file mode 100644 index 00000000..f599e28b --- /dev/null +++ b/packaging/debian/compat @@ -0,0 +1 @@ +10 diff --git a/packaging/debian/control.focal b/packaging/debian/control.focal new file mode 100644 index 00000000..0cf376d8 --- /dev/null +++ b/packaging/debian/control.focal @@ -0,0 +1,18 @@ +Source: clang-uml +Maintainer: Bartek Kryza +Section: devel +Priority: optional +Build-Depends: debhelper, make, gcc-10, g++-10, cmake (>= 3.16), libyaml-cpp-dev, llvm-12, llvm-12-dev, clang-12, libclang-12-dev, libclang-cpp12-dev +Standards-Version: 4.3.0 +Vcs-Browser: https://github.com/bkryza/clang-uml +Vcs-Git: https://github.com/bkryza/clang-uml.git +Homepage: https://github.com/bkryza/clang-uml + +Package: clang-uml +Architecture: any +Section: utils +Depends: ${misc:Depends}, ${shlibs:Depends} +Pre-Depends: ${misc:Pre-Depends} +Description: Automatic C++ UML diagram generator based on Clang. + . + This package provides the clang-uml binary. diff --git a/packaging/debian/control.jammy b/packaging/debian/control.jammy new file mode 100644 index 00000000..89ac8adf --- /dev/null +++ b/packaging/debian/control.jammy @@ -0,0 +1,18 @@ +Source: clang-uml +Maintainer: Bartek Kryza +Section: devel +Priority: optional +Build-Depends: debhelper, make, gcc-12, g++-12, cmake (>= 3.16), libyaml-cpp-dev, llvm-14, llvm-14-dev, clang-14, libclang-14-dev, libclang-cpp14-dev +Standards-Version: 4.3.0 +Vcs-Browser: https://github.com/bkryza/clang-uml +Vcs-Git: https://github.com/bkryza/clang-uml.git +Homepage: https://github.com/bkryza/clang-uml + +Package: clang-uml +Architecture: any +Section: utils +Depends: ${misc:Depends}, ${shlibs:Depends} +Pre-Depends: ${misc:Pre-Depends} +Description: Automatic C++ UML diagram generator based on Clang. + . + This package provides the clang-uml binary. diff --git a/packaging/debian/copyright b/packaging/debian/copyright new file mode 100644 index 00000000..bd54f076 --- /dev/null +++ b/packaging/debian/copyright @@ -0,0 +1,16 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: clang-uml +Source: https://github.com/bkryza/clang-uml + +Files: * +Copyright: 2021-2022 Bartek Kryza +License: apache + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packaging/debian/rules b/packaging/debian/rules new file mode 100755 index 00000000..99626ef6 --- /dev/null +++ b/packaging/debian/rules @@ -0,0 +1,14 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 +export CLANGUML_GIT_TOPLEVEL_DIR=$(CURDIR) +export CLANGUML_GIT_REVISION={{VERSION}} +export CLANGUML_GIT_BRANCH={{GIT_BRANCH}} +export CLANGUML_GIT_COMMIT={{GIT_COMMIT}} + +override_dh_auto_configure: + dh_auto_configure --buildsystem=cmake -- -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/usr -DGIT_VERSION={{VERSION}} + + +%: + dh $@ diff --git a/packaging/debian/source/format b/packaging/debian/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/packaging/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/packaging/debian/watch b/packaging/debian/watch new file mode 100644 index 00000000..1f8c2b0a --- /dev/null +++ b/packaging/debian/watch @@ -0,0 +1,3 @@ +version=4 + +https://github.com/bkryza/clang-uml/releases .*/[relasymcp.-]*(\d\S*)\.tar\.gz diff --git a/src/class_diagram/model/class_method.h b/src/class_diagram/model/class_method.h index f35ad492..277cd3c2 100644 --- a/src/class_diagram/model/class_method.h +++ b/src/class_diagram/model/class_method.h @@ -30,6 +30,8 @@ public: class_method(common::model::access_t access, const std::string &name, const std::string &type); + virtual ~class_method() = default; + bool is_pure_virtual() const; void is_pure_virtual(bool is_pure_virtual); diff --git a/src/class_diagram/model/enum.h b/src/class_diagram/model/enum.h index ef6025ce..e6d93a7b 100644 --- a/src/class_diagram/model/enum.h +++ b/src/class_diagram/model/enum.h @@ -30,9 +30,9 @@ public: enum_(const common::model::namespace_ &using_namespaces); enum_(const enum_ &) = delete; - enum_(enum_ &&) = default; + enum_(enum_ &&) = delete; enum_ &operator=(const enum_ &) = delete; - enum_ &operator=(enum_ &&) = default; + enum_ &operator=(enum_ &&) = delete; // TODO: Do we need this? friend bool operator==(const enum_ &l, const enum_ &r); diff --git a/src/common/model/diagram_filter.h b/src/common/model/diagram_filter.h index 9fa73c42..2e27815f 100644 --- a/src/common/model/diagram_filter.h +++ b/src/common/model/diagram_filter.h @@ -58,6 +58,8 @@ class filter_visitor { public: filter_visitor(filter_t type); + virtual ~filter_visitor() = default; + virtual tvl::value_t match( const diagram &d, const common::model::element &e) const; @@ -86,6 +88,8 @@ struct anyof_filter : public filter_visitor { anyof_filter( filter_t type, std::vector> filters); + virtual ~anyof_filter() = default; + tvl::value_t match( const diagram &d, const common::model::element &e) const override; @@ -99,6 +103,8 @@ private: struct namespace_filter : public filter_visitor { namespace_filter(filter_t type, std::vector namespaces); + virtual ~namespace_filter() = default; + tvl::value_t match(const diagram &d, const namespace_ &ns) const override; tvl::value_t match(const diagram &d, const element &e) const override; @@ -110,6 +116,8 @@ private: struct element_filter : public filter_visitor { element_filter(filter_t type, std::vector elements); + virtual ~element_filter() = default; + tvl::value_t match(const diagram &d, const element &e) const override; private: @@ -119,6 +127,8 @@ private: struct subclass_filter : public filter_visitor { subclass_filter(filter_t type, std::vector roots); + virtual ~subclass_filter() = default; + tvl::value_t match(const diagram &d, const element &e) const override; private: @@ -137,6 +147,8 @@ struct edge_traversal_filter : public filter_visitor { { } + virtual ~edge_traversal_filter() = default; + tvl::value_t match(const diagram &d, const MatchOverrideT &e) const override { // This filter should only be run on the completely generated diagram @@ -203,7 +215,7 @@ private: decltype(matching_elements_) parents; util::for_each( - matching_elements_, [this, &cd, &parents](const auto &element) { + matching_elements_, [&cd, &parents](const auto &element) { auto parent = detail::get( cd, element.get().path().to_string()); @@ -269,6 +281,8 @@ struct relationship_filter : public filter_visitor { relationship_filter( filter_t type, std::vector relationships); + virtual ~relationship_filter() = default; + tvl::value_t match( const diagram &d, const relationship_t &r) const override; @@ -279,6 +293,8 @@ private: struct access_filter : public filter_visitor { access_filter(filter_t type, std::vector access); + virtual ~access_filter() = default; + tvl::value_t match(const diagram &d, const access_t &a) const override; private: @@ -288,6 +304,8 @@ private: struct context_filter : public filter_visitor { context_filter(filter_t type, std::vector context); + virtual ~context_filter() = default; + tvl::value_t match(const diagram &d, const element &r) const override; private: @@ -298,6 +316,8 @@ struct paths_filter : public filter_visitor { paths_filter(filter_t type, const std::filesystem::path &root, std::vector p); + virtual ~paths_filter() = default; + tvl::value_t match( const diagram &d, const common::model::source_file &r) const override; diff --git a/src/common/model/path.h b/src/common/model/path.h index 44571bb3..c447f384 100644 --- a/src/common/model/path.h +++ b/src/common/model/path.h @@ -41,11 +41,11 @@ public: path(const path &right) { path_ = right.path_; } - path &operator=(const path &right) noexcept = default; + path &operator=(const path &right) = default; path(path &&right) noexcept = default; - path &operator=(path &&right) noexcept = default; + path &operator=(path &&right) = default; path(std::initializer_list ns) { diff --git a/src/include_diagram/generators/plantuml/include_diagram_generator.cc b/src/include_diagram/generators/plantuml/include_diagram_generator.cc index 3dddb099..b670a55b 100644 --- a/src/include_diagram/generators/plantuml/include_diagram_generator.cc +++ b/src/include_diagram/generators/plantuml/include_diagram_generator.cc @@ -46,11 +46,11 @@ void generator::generate_relationships( else { util::for_each_if( f.relationships(), - [this, &f](const auto &r) { + [this](const auto &r) { return m_model.should_include(r.type()) && util::contains(m_generated_aliases, r.destination()); }, - [this, &f, &ostr](const auto &r) { + [&f, &ostr](const auto &r) { ostr << f.alias() << " " << plantuml_common::to_plantuml(r.type(), r.style()) << " " << r.destination() << '\n'; diff --git a/src/include_diagram/model/diagram.h b/src/include_diagram/model/diagram.h index 81082e9c..a9a1268b 100644 --- a/src/include_diagram/model/diagram.h +++ b/src/include_diagram/model/diagram.h @@ -43,7 +43,7 @@ public: common::model::diagram_t type() const override; type_safe::optional_ref get( - const std::string &full_name) const; + const std::string &full_name) const override; void add_file(std::unique_ptr &&f); diff --git a/src/main.cc b/src/main.cc index 8ffe930b..0c6431c5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -21,8 +21,8 @@ #include "include_diagram/generators/plantuml/include_diagram_generator.h" #include "package_diagram/generators/plantuml/package_diagram_generator.h" #include "sequence_diagram/generators/plantuml/sequence_diagram_generator.h" - #include "util/util.h" +#include "version.h" #include #include @@ -38,6 +38,8 @@ using namespace clanguml; using config::config; +void print_version(); + void print_diagrams_list(const clanguml::config::config &cfg); bool check_output_directory(const std::string &dir); @@ -55,6 +57,7 @@ int main(int argc, const char *argv[]) std::vector diagram_names{}; std::optional output_directory; unsigned int thread_count{0}; + bool show_version{false}; bool verbose{false}; bool list_diagrams{false}; @@ -68,12 +71,18 @@ int main(int argc, const char *argv[]) "Override output directory specified in config file"); app.add_option("-t,--thread-count", thread_count, "Thread pool size (0 = hardware concurrency)"); + app.add_flag("-V,--version", show_version, "Print version and exit"); app.add_flag("-v,--verbose", verbose, "Verbose logging"); app.add_flag("-l,--list-diagrams", list_diagrams, "Print list of diagrams defined in the config file"); CLI11_PARSE(app, argc, argv); + if (show_version) { + print_version(); + return 0; + } + clanguml::util::setup_logging(verbose); clanguml::config::config config; @@ -223,6 +232,15 @@ bool check_output_directory(const std::string &dir) return true; } +void print_version() +{ + std::cout << "clang-uml " << clanguml::version::CLANG_UML_VERSION << '\n'; + std::cout << "Copyright (C) 2021-2022 Bartek Kryza " + << '\n'; + std::cout << "Built with libclang: " + << clanguml::version::CLANG_UML_LIBCLANG_VERSION << std::endl; +} + void print_diagrams_list(const clanguml::config::config &cfg) { using std::cout; diff --git a/src/package_diagram/model/diagram.h b/src/package_diagram/model/diagram.h index 0511141d..253d8f45 100644 --- a/src/package_diagram/model/diagram.h +++ b/src/package_diagram/model/diagram.h @@ -45,7 +45,7 @@ public: packages() const; type_safe::optional_ref get( - const std::string &full_name) const; + const std::string &full_name) const override; void add_package(std::unique_ptr &&p); diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index cf15c3de..552f0f79 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -37,7 +37,7 @@ public: common::model::diagram_t type() const override; type_safe::optional_ref get( - const std::string &full_name) const; + const std::string &full_name) const override; std::string to_alias(const std::string &full_name) const; diff --git a/src/util/util.cc b/src/util/util.cc index 7a4c2165..cefa989f 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -56,8 +56,23 @@ std::string get_process_output(const std::string &command) return result; } +std::string get_env(const std::string &name) +{ + const char *value = std::getenv(name.c_str()); + + if (value == nullptr) + return {}; + + return std::string{value}; +} + bool is_git_repository() { + const auto env = get_env("CLANGUML_GIT_COMMIT"); + + if (!env.empty()) + return true; + #if defined(_WIN32) || defined(_WIN64) return false; #else @@ -69,21 +84,41 @@ bool is_git_repository() std::string get_git_branch() { + const auto env = get_env("CLANGUML_GIT_BRANCH"); + + if (!env.empty()) + return env; + return trim(get_process_output("git rev-parse --abbrev-ref HEAD")); } std::string get_git_revision() { + const auto env = get_env("CLANGUML_GIT_REVISION"); + + if (!env.empty()) + return env; + return trim(get_process_output("git describe --tags --always")); } std::string get_git_commit() { + const auto env = get_env("CLANGUML_GIT_COMMIT"); + + if (!env.empty()) + return env; + return trim(get_process_output("git rev-parse HEAD")); } std::string get_git_toplevel_dir() { + const auto env = get_env("CLANGUML_GIT_TOPLEVEL_DIR"); + + if (!env.empty()) + return env; + return trim(get_process_output("git rev-parse --show-toplevel")); } diff --git a/src/util/util.h b/src/util/util.h index abf1a84e..b01e17f8 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -62,6 +62,8 @@ void setup_logging(bool verbose); std::string get_process_output(const std::string &command); +std::string get_env(const std::string &name); + bool is_git_repository(); std::string get_git_branch(); diff --git a/src/version.h.in b/src/version.h.in new file mode 100644 index 00000000..fb0a72a7 --- /dev/null +++ b/src/version.h.in @@ -0,0 +1,23 @@ +/** + * src/version.h + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace clanguml::version { +static constexpr auto CLANG_UML_VERSION = "@GIT_VERSION@"; +static constexpr auto CLANG_UML_LIBCLANG_VERSION = "@LIBCLANG_VERSION_STRING@"; +} // namespace clanguml::version \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 506fb9fb..4c02f600 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,139 +1,65 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.12) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_FLAGS "-std=c++17 ${LIBCLANG_CXXFLAGS}") +set(TEST_DISABLE_WARNINGS "-Wno-unused-parameter -Wno-unused-variable -Wno-attributes") + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCLANG_CXXFLAGS} ${TEST_DISABLE_WARNINGS}") file(GLOB_RECURSE TEST_CASE_SOURCES t*/*.cc) file(GLOB_RECURSE TEST_CASE_CONFIGS t*/.clang-uml) file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml) -set(CLANG_UML_TEST_UTIL_SRC - test_util.cc - ${TEST_UTIL_SOURCES} -) -set(CLANG_UML_TEST_UTIL_HEADER - catch.h -) +set(CLANG_UML_TEST_LIBRARIES + ${LIBCLANG_LIBRARIES} + ${YAML_CPP_LIBRARIES} + clang-umllib + cppast + Threads::Threads) -set(CLANG_UML_TEST_MODEL_SRC - test_model.cc - ${TEST_MODEL_SOURCES} - ) -set(CLANG_UML_TEST_MODEL_HEADER - catch.h - ) +set(CLANG_UML_TEST_UTIL_SRC test_util.cc ${TEST_UTIL_SOURCES}) +set(CLANG_UML_TEST_UTIL_HEADER catch.h) -set(CLANG_UML_TEST_CASES_SRC - test_cases.cc - ${TEST_CASE_SOURCES} -) -set(CLANG_UML_TEST_CASES_HEADER - catch.h -) +set(CLANG_UML_TEST_MODEL_SRC test_model.cc ${TEST_MODEL_SOURCES}) +set(CLANG_UML_TEST_MODEL_HEADER catch.h) -set(CLANG_UML_TEST_DECORATOR_PARSER_SRC - test_decorator_parser.cc - ${TEST_UTIL_SOURCES} -) -set(CLANG_UML_TEST_DECORATOR_PARSER_HEADER - catch.h -) +set(CLANG_UML_TEST_CASES_SRC test_cases.cc ${TEST_CASE_SOURCES}) +set(CLANG_UML_TEST_CASES_HEADER catch.h) -set(CLANG_UML_TEST_CONFIG_SRC - test_config.cc - ${TEST_UTIL_SOURCES} - ) -set(CLANG_UML_TEST_CONFIG_HEADER - catch.h - ) +set(CLANG_UML_TEST_DECORATOR_PARSER_SRC test_decorator_parser.cc ${TEST_UTIL_SOURCES}) +set(CLANG_UML_TEST_DECORATOR_PARSER_HEADER catch.h) -set(CLANG_UML_TEST_FILTERS_SRC - test_filters.cc - ${TEST_FILTERS_SOURCES} - ) -set(CLANG_UML_TEST_FILTERS_HEADER - catch.h - ) +set(CLANG_UML_TEST_CONFIG_SRC test_config.cc ${TEST_UTIL_SOURCES}) +set(CLANG_UML_TEST_CONFIG_HEADER catch.h) -set(CLANG_UML_TEST_THREAD_POOL_EXECUTOR_SRC - test_thread_pool_executor.cc - ) -set(CLANG_UML_TEST_THREAD_POOL_EXECUTOR_HEADER - catch.h - ) +set(CLANG_UML_TEST_FILTERS_SRC test_filters.cc ${TEST_FILTERS_SOURCES}) +set(CLANG_UML_TEST_FILTERS_HEADER catch.h) -add_executable(test_util - ${CLANG_UML_TEST_UTIL_SRC} - ${CLANG_UML_TEST_UTIL_HEADER}) +set(CLANG_UML_TEST_THREAD_POOL_EXECUTOR_SRC test_thread_pool_executor.cc) +set(CLANG_UML_TEST_THREAD_POOL_EXECUTOR_HEADER catch.h) -target_link_libraries(test_util - PRIVATE - ${LIBCLANG_LIBRARIES} - ${YAML_CPP_LIBRARIES} - clang-umllib cppast) +add_executable(test_util ${CLANG_UML_TEST_UTIL_SRC} ${CLANG_UML_TEST_UTIL_HEADER}) +target_link_libraries(test_util PRIVATE ${CLANG_UML_TEST_LIBRARIES}) -add_executable(test_model - ${CLANG_UML_TEST_MODEL_SRC} - ${CLANG_UML_TEST_MODEL_HEADER}) +add_executable(test_model ${CLANG_UML_TEST_MODEL_SRC} ${CLANG_UML_TEST_MODEL_HEADER}) +target_link_libraries(test_model PRIVATE ${CLANG_UML_TEST_LIBRARIES}) -target_link_libraries(test_model - PRIVATE - ${LIBCLANG_LIBRARIES} - ${YAML_CPP_LIBRARIES} - clang-umllib cppast) +add_executable(test_decorator_parser ${CLANG_UML_TEST_DECORATOR_PARSER_SRC} ${CLANG_UML_TEST_DECORATOR_PARSER_HEADER}) +target_link_libraries(test_decorator_parser PRIVATE ${CLANG_UML_TEST_LIBRARIES}) -add_executable(test_decorator_parser - ${CLANG_UML_TEST_DECORATOR_PARSER_SRC} - ${CLANG_UML_TEST_DECORATOR_PARSER_HEADER}) +add_executable(test_config ${CLANG_UML_TEST_CONFIG_SRC} ${CLANG_UML_TEST_CONFIG_HEADER}) +target_link_libraries(test_config PRIVATE ${CLANG_UML_TEST_LIBRARIES}) -target_link_libraries(test_decorator_parser - PRIVATE - ${LIBCLANG_LIBRARIES} - ${YAML_CPP_LIBRARIES} - clang-umllib cppast) +add_executable(test_filters ${CLANG_UML_TEST_FILTERS_SRC} ${CLANG_UML_TEST_FILTERS_HEADER}) +target_link_libraries(test_filters PRIVATE ${CLANG_UML_TEST_LIBRARIES}) -add_executable(test_config - ${CLANG_UML_TEST_CONFIG_SRC} - ${CLANG_UML_TEST_CONFIG_HEADER}) +add_executable(test_thread_pool_executor ${CLANG_UML_TEST_THREAD_POOL_EXECUTOR_SRC} ${CLANG_UML_TEST_THREAD_POOL_EXECUTOR_HEADER}) +target_link_libraries(test_thread_pool_executor PRIVATE ${CLANG_UML_TEST_LIBRARIES}) -target_link_libraries(test_config - PRIVATE - ${LIBCLANG_LIBRARIES} - ${YAML_CPP_LIBRARIES} - clang-umllib cppast) - -add_executable(test_filters - ${CLANG_UML_TEST_FILTERS_SRC} - ${CLANG_UML_TEST_FILTERS_HEADER}) - -target_link_libraries(test_filters - PRIVATE - ${LIBCLANG_LIBRARIES} - ${YAML_CPP_LIBRARIES} - clang-umllib cppast) - -add_executable(test_thread_pool_executor - ${CLANG_UML_TEST_THREAD_POOL_EXECUTOR_SRC} - ${CLANG_UML_TEST_THREAD_POOL_EXECUTOR_HEADER}) - -target_link_libraries(test_thread_pool_executor - PRIVATE - ${LIBCLANG_LIBRARIES} - ${YAML_CPP_LIBRARIES} - clang-umllib cppast) - -add_executable(test_cases - ${CLANG_UML_TEST_CASES_SRC} - ${CLANG_UML_TEST_CASES_HEADER}) - -target_link_libraries(test_cases - PRIVATE - ${LIBCLANG_LIBRARIES} - ${YAML_CPP_LIBRARIES} - clang-umllib cppast) +add_executable(test_cases ${CLANG_UML_TEST_CASES_SRC} ${CLANG_UML_TEST_CASES_HEADER}) +target_link_libraries(test_cases PRIVATE ${CLANG_UML_TEST_LIBRARIES}) foreach(TEST_CASE_CONFIG ${TEST_CASE_CONFIGS}) file(RELATIVE_PATH diff --git a/tests/t00012/t00012.cc b/tests/t00012/t00012.cc index c2a79d73..82f292a0 100644 --- a/tests/t00012/t00012.cc +++ b/tests/t00012/t00012.cc @@ -1,6 +1,6 @@ #include +#include #include -#include #include #include #include diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 02683907..6abba504 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -55,7 +55,7 @@ generate_sequence_diagram(cppast::libclang_compilation_database &db, diagram_config, diagram_visitor>(db, diagram->name, dynamic_cast(*diagram)); - return std::move(model); + return model; } std::unique_ptr generate_class_diagram( @@ -73,7 +73,7 @@ std::unique_ptr generate_class_diagram( diagram_config, diagram_visitor>( db, diagram->name, dynamic_cast(*diagram)); - return std::move(model); + return model; } std::unique_ptr diff --git a/thirdparty/cppast b/thirdparty/cppast index 7fe5f2be..fec53b1e 160000 --- a/thirdparty/cppast +++ b/thirdparty/cppast @@ -1 +1 @@ -Subproject commit 7fe5f2be3f8ae2b90e857bbea54df47b45eb64b9 +Subproject commit fec53b1e99e8c4358811d9d0571e488058620386