From cfb91aa253d472fa9867dcedaa8a491de828a5ce Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Tue, 28 Jan 2025 09:59:46 +0100 Subject: [PATCH 01/18] deploy(conan): +Conan v2 recipe --- .gitignore | 12 +- CMakeLists.txt | 10 +- cmake/add_llvm.cmake | 11 +- cmake/phasar_macros.cmake | 90 +++- conanfile.py | 297 ++++++++++ include/phasar/Utils/GraphTraits.h | 12 + lib/CMakeLists.txt | 3 + .../DataFlow/PathSensitivity/CMakeLists.txt | 2 +- test_package/CMakeLists.txt | 13 + test_package/conanfile.py | 26 + test_package/example.ll | 170 ++++++ test_package/myphasartool.cpp | 58 ++ test_package/test.sh | 8 + .../DataFlow/PathSensitivity/CMakeLists.txt | 2 +- ...00-force-import-original-llvm-config.patch | 12 + utils/conan/clang/conandata.yml | 12 + utils/conan/clang/conanfile.py | 281 ++++++++++ utils/conan/clang/test_package/CMakeLists.txt | 16 + utils/conan/clang/test_package/conanfile.py | 38 ++ .../conan/clang/test_package/test_package.cpp | 35 ++ utils/conan/llvm-core/all/conandata.yml | 25 + utils/conan/llvm-core/all/conanfile.py | 507 ++++++++++++++++++ .../patches/14x/0000-cmake-dependencies.patch | 93 ++++ .../14x/0001-calculate-job-pools.patch | 44 ++ .../patches/14x/0002-missing-includes.patch | 12 + .../0003-no-build-with-install-rpath.patch | 13 + .../patches/14x/0004-remove-lto-exports.patch | 32 ++ .../llvm-core/all/test_package/CMakeLists.txt | 31 ++ .../llvm-core/all/test_package/conanfile.py | 43 ++ .../all/test_package/test_function.ll | 6 + .../all/test_package/test_package.cpp | 38 ++ 31 files changed, 1933 insertions(+), 19 deletions(-) create mode 100644 conanfile.py create mode 100644 test_package/CMakeLists.txt create mode 100644 test_package/conanfile.py create mode 100644 test_package/example.ll create mode 100644 test_package/myphasartool.cpp create mode 100755 test_package/test.sh create mode 100644 utils/conan/clang/14x/0000-force-import-original-llvm-config.patch create mode 100644 utils/conan/clang/conandata.yml create mode 100644 utils/conan/clang/conanfile.py create mode 100644 utils/conan/clang/test_package/CMakeLists.txt create mode 100644 utils/conan/clang/test_package/conanfile.py create mode 100644 utils/conan/clang/test_package/test_package.cpp create mode 100644 utils/conan/llvm-core/all/conandata.yml create mode 100644 utils/conan/llvm-core/all/conanfile.py create mode 100644 utils/conan/llvm-core/all/patches/14x/0000-cmake-dependencies.patch create mode 100644 utils/conan/llvm-core/all/patches/14x/0001-calculate-job-pools.patch create mode 100644 utils/conan/llvm-core/all/patches/14x/0002-missing-includes.patch create mode 100644 utils/conan/llvm-core/all/patches/14x/0003-no-build-with-install-rpath.patch create mode 100644 utils/conan/llvm-core/all/patches/14x/0004-remove-lto-exports.patch create mode 100644 utils/conan/llvm-core/all/test_package/CMakeLists.txt create mode 100644 utils/conan/llvm-core/all/test_package/conanfile.py create mode 100644 utils/conan/llvm-core/all/test_package/test_function.ll create mode 100644 utils/conan/llvm-core/all/test_package/test_package.cpp diff --git a/.gitignore b/.gitignore index 1cc71e473..df7dd6a47 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,11 @@ bin/* # build directories for cmake -build/ -build_*/ -build-*/ +build*/ +cmake-build*/ +cmake-install*/ +CMakeUserPresets.json +venv/ # LLVM project llvm-project/* @@ -26,6 +28,7 @@ doc/* # log/ directory log/* +**/*/logs/ # CMake build dir build/* @@ -49,6 +52,9 @@ build/* # ignore all auto-generated LLVM IR code *.ll +!utils/conan/llvm-core/all/test_package/test_function.ll +!test_package/example.ll +!test_package_cmake/example.ll # auto generated test files *.test diff --git a/CMakeLists.txt b/CMakeLists.txt index 9743e3ad8..593c04291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ option(PHASAR_BUILD_DOC "Build documentation" OFF) option(PHASAR_DEBUG_LIBDEPS "Debug internal library dependencies (private linkage)" OFF) option(PHASAR_BUILD_TOOLS "Build PhASAR-based tools (default is ON)" ${PHASAR_BUILD_OPTIONAL_TARGETS_DEFAULT}) +option(PHASAR_USE_CONAN "Using Conan for dependencies instead of submodules." OFF) #option(BUILD_SHARED_LIBS "Build shared libraries (default is ON)" ON) option(PHASAR_BUILD_DYNLIB "Build one fat shared library. Requires BUILD_SHARED_LIBS to be turned OFF (default is OFF)" OFF) @@ -299,6 +300,13 @@ if(SQLite3_FOUND) else() set(PHASAR_HAS_SQLITE OFF) endif() +# Print all variables set by LLVM +get_cmake_property(all_variables VARIABLES) +foreach(var ${all_variables}) + if(var MATCHES "^LLVM_") + message(STATUS "${var} = ${${var}}") + endif() +endforeach() option(USE_LLVM_FAT_LIB "Link against libLLVM.so instead of the individual LLVM libraries if possible (default is OFF; always on if BUILD_SHARED_LIBS is ON)" OFF) @@ -315,7 +323,7 @@ if(PHASAR_USE_Z3 AND NOT PHASAR_IN_TREE) # as it lacks some functionality (such as z3::expr::simplify()) that we require find_package(Z3 4.7.1 REQUIRED) - if(NOT TARGET z3) + if(NOT TARGET z3 ) add_library(z3 IMPORTED SHARED) set_property(TARGET z3 PROPERTY IMPORTED_LOCATION ${Z3_LIBRARIES}) diff --git a/cmake/add_llvm.cmake b/cmake/add_llvm.cmake index 7cf3ceb94..8fae6dc4b 100644 --- a/cmake/add_llvm.cmake +++ b/cmake/add_llvm.cmake @@ -13,7 +13,9 @@ macro(add_llvm) set(USE_LLVM_FAT_LIB ON) endif() - if (NOT USE_LLVM_FAT_LIB) + if (PHASAR_USE_CONAN) + set(LLVM_ENABLE_RTTI ON) + elseif (NOT USE_LLVM_FAT_LIB) message(STATUS "Link against individual LLVM modules") set(LLVM_REQUIRED_LIBRARIES Core @@ -42,7 +44,7 @@ macro(add_llvm) message(WARNING "Did not find the LLVM modules ${LLVM_SMALL_LIB_NOTFOUND_PRETTY}. Fallback to link against ${LLVM_LIBRARY}. To silence this warning, set -DUSE_LLVM_FAT_LIB=ON in the cmake invocation.") endif() endif(DEFINED LLVM_SMALL_LIB_NOTFOUND) - endif(NOT USE_LLVM_FAT_LIB) + endif() endif(NOT PHASAR_IN_TREE) if(NOT LLVM_ENABLE_RTTI AND NOT PHASAR_IN_TREE) @@ -53,7 +55,10 @@ endmacro() macro(add_clang) # The clang-cpp shared library is now the preferred way to link dynamically against libclang if we build out of tree. - if(NOT PHASAR_IN_TREE) + if (PHASAR_USE_CONAN) + find_package(Clang REQUIRED) + set(CLANG_LIBRARY clangCodeGen clangTooling) + elseif(NOT PHASAR_IN_TREE) find_library(CLANG_LIBRARY NAMES clang-cpp libclang-cpp HINTS ${LLVM_LIBRARY_DIRS}) if(${CLANG_LIBRARY} STREQUAL "CLANG_LIBRARY-NOTFOUND") set(NEED_LIBCLANG_COMPONENT_LIBS ON) diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index 2ce5cd45f..78dd7807a 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -26,7 +26,7 @@ function(add_phasar_unittest test_name) target_link_libraries(${test} PRIVATE phasar - gtest + GTest::gtest ) add_test(NAME "${test}" @@ -37,11 +37,80 @@ function(add_phasar_unittest test_name) set(CTEST_OUTPUT_ON_FAILURE ON) endfunction() +function(validate_binary_version result item) + message(STATUS " - validate_binary_version of \"${item}\"") + execute_process( + COMMAND "${item}" --version + OUTPUT_VARIABLE output + ERROR_VARIABLE error + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + string(REGEX MATCH " version 14\\." match "${output}") + if (match) + set(${result} TRUE PARENT_SCOPE) + else() + set(${result} FALSE PARENT_SCOPE) + endif() +endfunction() + function(generate_ll_file) set(options MEM2REG DEBUG O1 O2 O3) set(testfile FILE) cmake_parse_arguments(GEN_LL "${options}" "${testfile}" "" ${ARGN}) + if (NOT clang) + # Conan deps are available in in PATH + foreach(hint "${LLVM_TOOLS_BINARY_DIR}" "${Clang_INCLUDE_DIR}/../bin" "${LLVM_INCLUDE_DIR}/../bin" "/usr/local/llvm-14/bin") + cmake_path(NORMAL_PATH hint OUTPUT_VARIABLE hint) + list(APPEND binary_hint_paths "${hint}") + endforeach() + message(STATUS "HINTS to find clang/clang++/opt: ${binary_hint_paths}") + + if ("${CMAKE_VERSION}" VERSION_LESS "3.25") # VALIDATOR requires it + + find_program(clang REQUIRED + NAMES clang-14 clang + HINTS ${binary_hint_paths}) + find_program(clangcpp REQUIRED + NAMES clang++ + HINTS ${binary_hint_paths}) + find_program(opt REQUIRED + NAMES opt + HINTS ${binary_hint_paths}) + + set(IS_VALID_VERSION "") + validate_binary_version("IS_VALID_VERSION" "${clang}") + if (NOT "${IS_VALID_VERSION}") + message(FATAL_ERROR "Couldn't find clang in version 14") + endif() + validate_binary_version("IS_VALID_VERSION" "${clangcpp}") + if (NOT "${IS_VALID_VERSION}") + message(FATAL_ERROR "Couldn't find clang++ in version 14") + endif() + validate_binary_version("IS_VALID_VERSION" "${opt}") + if (NOT "${IS_VALID_VERSION}") + message(FATAL_ERROR "Couldn't find opt in version 14") + endif() + else() + find_program(clang REQUIRED + NAMES clang-14 clang + HINTS ${binary_hint_paths} + VALIDATOR validate_binary_version) + message(STATUS "found clang binary in \"${clang}\"") + find_program(clangcpp REQUIRED + NAMES clang++ + HINTS ${binary_hint_paths} + VALIDATOR validate_binary_version) + message(STATUS "found clang binary in \"${clangpp}\"") + find_program(opt REQUIRED + NAMES opt + HINTS ${binary_hint_paths} + VALIDATOR validate_binary_version) + message(STATUS "found clang binary in \"${opt}\"") + endif() + endif() + # get file extension get_filename_component(test_code_file_ext ${GEN_LL_FILE} EXT) string(REPLACE "." "_" ll_file_suffix ${test_code_file_ext}) @@ -76,12 +145,13 @@ function(generate_ll_file) set(GEN_C_FLAGS -fno-discard-value-names -emit-llvm -S -w) set(GEN_CMD_COMMENT "[LL]") - if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) - list(APPEND GEN_CXX_FLAGS -Xclang -no-opaque-pointers) - endif() - if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15) - list(APPEND GEN_C_FLAGS -Xclang -no-opaque-pointers) - endif() + # uncomment with branch f-TestingAPIChanges + # if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) + # list(APPEND GEN_CXX_FLAGS -Xclang -no-opaque-pointers) + # endif() + # if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15) + # list(APPEND GEN_C_FLAGS -Xclang -no-opaque-pointers) + # endif() if(GEN_LL_MEM2REG) list(APPEND GEN_CXX_FLAGS -Xclang -disable-O0-optnone) @@ -117,10 +187,10 @@ function(generate_ll_file) # define .ll file generation command if(${test_code_file_ext} STREQUAL ".cpp") - set(GEN_CMD ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}) + set(GEN_CMD ${CMAKE_CXX_COMPILER_LAUNCHER} ${clangcpp}) list(APPEND GEN_CMD ${GEN_CXX_FLAGS}) else() - set(GEN_CMD ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) + set(GEN_CMD ${CMAKE_C_COMPILER_LAUNCHER} ${clang}) list(APPEND GEN_CMD ${GEN_C_FLAGS}) endif() @@ -128,7 +198,7 @@ function(generate_ll_file) add_custom_command( OUTPUT ${test_code_ll_file} COMMAND ${GEN_CMD} ${test_code_file_path} -o ${test_code_ll_file} - COMMAND ${CMAKE_CXX_COMPILER_LAUNCHER} opt -mem2reg -S -opaque-pointers=0 ${test_code_ll_file} -o ${test_code_ll_file} + COMMAND ${CMAKE_CXX_COMPILER_LAUNCHER} ${opt} -mem2reg -S -opaque-pointers=0 ${test_code_ll_file} -o ${test_code_ll_file} COMMENT ${GEN_CMD_COMMENT} DEPENDS ${GEN_LL_FILE} VERBATIM diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 000000000..ced7a9bed --- /dev/null +++ b/conanfile.py @@ -0,0 +1,297 @@ +from conan import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps +from conan.tools.build import check_min_cppstd +from conan.tools.files import ( + apply_conandata_patches, + collect_libs, + get, + rmdir, + load, + save, + copy, + export_conandata_patches, + rm, + rename, + replace_in_file +) +from conan.tools.scm import Git +from os.path import join +import re +from pathlib import Path, PurePosixPath +import textwrap +import json + +def components_from_dotfile(dotfile): + def node_labels(dot): + label_replacements = { + "LibXml2::LibXml2": "libxml2::libxml2", + "ZLIB::ZLIB": "zlib::zlib", + "zstd::libzstd_static": "zstd::zstdlib", + "-lpthread": "pthread", + "curl": "libcurl::libcurl", + } + for row in dot: + # e.g. "node0" [ label = "phasar\n(phasar::phasar)", shape = octagon ]; + match_label = re.match(r'''^\s*"(node[0-9]+)"\s*\[\s*label\s*=\s*"([^\\"]+)''', row) + if match_label: + node = match_label.group(1) + label = match_label.group(2) + if label.startswith("LLVM"): + yield node, f"llvm-core::{label}" + elif label.endswith("libsqlite3.a"): + yield node, "sqlite3::sqlite3" + elif label.endswith("libclang-cpp.so"): + yield node, "clang::clang" + else: + yield node, label_replacements.get(label, label) + + def node_dependencies(dot): + ignore_deps = [ + "nlohmann_json_schema_validator" + ] + labels = {k: v for k, v in node_labels(dot)} + # raise Exception(labels) + for row in dot: + # "node0" -> "node1" [ style = dashed ] // phasar -> LLVMAnalysis + match_dep = re.match(r'''^\s*"(node[0-9]+)"\s*->\s*"(node[0-9]+)".*''', row) + if match_dep: + node_label = labels[match_dep.group(1)] + dependency = labels[match_dep.group(2)] + if node_label.startswith("phasar") and PurePosixPath(dependency).parts[-1] not in ignore_deps: + yield node_label, labels[match_dep.group(2)] + # some components don't have dependencies + for label in labels.values(): + if label.startswith("phasar"): + yield label, None + + system_libs = { + "ole32", + "delayimp", + "shell32", + "advapi32", + "-delayload:shell32.dll", + "uuid", + "psapi", + "-delayload:ole32.dll", + "ntdll", + "ws2_32", + "rt", + "m", + "dl", + "pthread", + "stdc++fs" + } + components = {} + dotfile_rows = dotfile.split("\n") + for node, dependency in node_dependencies(dotfile_rows): + key = "system_libs" if dependency in system_libs else "requires" + if node not in components: + components[node] = { "system_libs": [], "requires": [] } + if dependency is not None: + components[node][key] = [dependency] + elif dependency is not None: + components[node][key].append(dependency) + + return components + +class PhasarRecipe(ConanFile): + name = "phasar" + package_type = "library" + + # Optional metadata + license = "MIT license" + author = " " + url = "https://github.com/secure-software-engineering/phasar" + description = "A LLVM-based static analysis framework. " + topics = ("LLVM", "PhASAR", "SAST") + + # Binary configuration + settings = "os", "compiler", "build_type", "arch" + options = { + "with_z3": [True, False], + "shared": [True, False], + "fPIC": [True, False], + "tests": [True, False], + "run_tests": [True, False], + "use_project_cmake_config": [True, False], + } + default_options = { + "with_z3": True, + "shared": False, + "fPIC": True, + "tests": False, + "run_tests": False, + "use_project_cmake_config": False + } + + @property + def _graphviz_file(self): + return PurePosixPath(self.build_folder) / "graph" / "phasar.dot" + + def set_version(self): + git = Git(self, self.recipe_folder) + # git.coordinates_to_conandata() + if self.version is None: + self.output.info("No version information set, retrieving from git.") + calver = git.run("show -s --date=format:'%Y.%m.%d' --format='%cd'") + short_hash = git.run("show -s --format='%h'") + self.version = f"{calver}+{short_hash}" + + def export_sources(self): + copy(self, "cmake/*", self.recipe_folder, self.export_sources_folder) + copy(self, "phasar/*", self.recipe_folder, self.export_sources_folder) + copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder) + + def layout(self): + cmake_layout(self) + + def config_options(self): + if self.settings.os == "Windows": + self.options.rm_safe("fPIC") + + def requirements(self): + self.requires("boost/[>1.72.0 <=1.81.0]") + self.requires("sqlite3/[>=3 <4]") + self.requires("libcurl/[>=7 <9]") + self.requires("clang/14.0.6", transitive_libs=True, transitive_headers=True) + self.requires("nlohmann_json/3.11.3", build=True, headers=True, libs=False, transitive_headers=True) + self.requires("json-schema-validator/2.3.0", build=True, headers=True, libs=False, transitive_headers=True) + + llvm_options={ + "rtti": True, + } + if self.options.with_z3: + self.requires("z3/[>=4.7.1 <5]") + llvm_options["with_z3"] = True + self.requires("llvm-core/14.0.6", transitive_libs=True, transitive_headers=True, options=llvm_options) + + def build_requirements(self): + self.tool_requires("cmake/[>=3.25.0 <4.0.0]") # find_program validator + self.tool_requires("ninja/[>=1.9.0 <2.0.0]") + if self.options.tests: + self.test_requires("gtest/1.14.0") + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def validate(self): + check_min_cppstd(self, '17') + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self, 'Ninja') + tc.generate() + + def _cmake_configure(self): + cmake = CMake(self) + self._handle_graphviz() + cmake.configure( + variables={ + 'PHASAR_USE_CONAN': True, + 'BUILD_SHARED_LIBS': self.options.shared, + 'PHASAR_BUILD_UNITTESTS': self.options.tests, + 'PHASAR_BUILD_IR': self.options.tests, + 'PHASAR_BUILD_DOC': False, + 'PHASAR_USE_Z3': self.options.with_z3, + 'USE_LLVM_FAT_LIB': False, + 'BUILD_PHASAR_CLANG': True, + # TODO + 'PHASAR_BUILD_TOOLS': False, + }, + cli_args=[ + f"--graphviz={self._graphviz_file}" + ] + ) + return cmake + + def _handle_graphviz(self): + exclude_patterns = [ + "LLVMTableGenGlobalISel.*", + "CONAN_LIB.*", + "LLVMExegesis.*", + "LLVMCFIVerify.*" + ] + graphviz_options = textwrap.dedent(f""" + set(GRAPHVIZ_EXECUTABLES OFF) + set(GRAPHVIZ_MODULE_LIBS OFF) + set(GRAPHVIZ_OBJECT_LIBS OFF) + set(GRAPHVIZ_IGNORE_TARGETS "{';'.join(exclude_patterns)}") + """) + save(self, PurePosixPath(self.build_folder) / "CMakeGraphVizOptions.cmake", graphviz_options) + + def build(self): + cmake = self._cmake_configure() + cmake.build() + if self.options.run_tests: + cmake.ctest(cli_args=[ + "--exclude-regex 'IDEExtendedTaintAnalysisTest.*'", # known flaky test + "--no-tests=error", + "--output-on-failure", + "--test-dir", + self.build_folder + ]) + + @property + def _cmake_module_path(self): + return PurePosixPath("lib") / "cmake" / "phasar" + + @property + def _build_info_file(self): + return PurePosixPath(self.package_folder) / self._cmake_module_path / "conan_phasar_build_info.json" + + def _write_build_info(self): + # maybe process original config + cmake_config = Path(self.package_folder / self._cmake_module_path / "phasarConfig.cmake").read_text("utf-8") + components = components_from_dotfile(load(self, self._graphviz_file)) + + build_info = { + "components": components, + } + + with open(self._build_info_file, "w", encoding="utf-8") as fp: + json.dump(build_info, fp, indent=2) + + return build_info + + def _read_build_info(self) -> dict: + with open(self._build_info_file, encoding="utf-8") as fp: + return json.load(fp) + + def package_id(self): + del self.info.options.tests + del self.info.options.run_tests + + def package(self): + copy(self, "LICENSE.txt", self.source_folder, join(self.package_folder, "licenses")) + + cmake = self._cmake_configure() + cmake.install() + if self.options.use_project_cmake_config: + rm(self, "phasarConfig*.cmake", join("lib", "cmake", "phasar")) + rm(self, "*target*.cmake", join("lib", "cmake", "phasar")) + + self._write_build_info() + + def package_info(self): + if self.options.use_project_cmake_config: + # disable CMakeDeps and use own CMakefiles: + self.cpp_info.set_property("cmake_find_mode", "none") + self.cpp_info.builddirs.append(join("lib", "cmake", "phasar")) + + else: + self.cpp_info.set_property("cmake_file_name", "phasar") + + build_info = self._read_build_info() + components = build_info["components"] + + for component_name, data in components.items(): + req = data["requires"] + sys = data["system_libs"] + self.output.info(f"{component_name}: \nrequires:{req}\nsystem:{sys}") + self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) + self.cpp_info.components[component_name].libs = [component_name] + self.cpp_info.components[component_name].requires = data["requires"] + self.cpp_info.components[component_name].system_libs = data["system_libs"] + diff --git a/include/phasar/Utils/GraphTraits.h b/include/phasar/Utils/GraphTraits.h index 76915be0f..d0c5032f5 100644 --- a/include/phasar/Utils/GraphTraits.h +++ b/include/phasar/Utils/GraphTraits.h @@ -101,6 +101,18 @@ concept is_reservable_graph_trait_v = is_graph_trait && {GraphTrait::reserve(g, size_t(0))}; }; +template +concept is_removable_graph_trait_v = is_graph_trait && + requires(typename GraphTrait::graph_type &g, + typename GraphTrait::vertex_t vtx, + typename GraphTrait::edge_iterator edge_it, + typename GraphTrait::roots_iterator root_it) { + typename GraphTrait::edge_iterator; + typename GraphTrait::roots_iterator; + {GraphTrait::removeEdge(g, vtx, edge_it)}; + {GraphTrait::removeRoot(g, root_it)}; +}; + #else namespace detail { template diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 86d4c048d..5cb0b04e8 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -36,6 +36,9 @@ set(PHASAR_LINK_LIBS phasar_llvm_ifdside phasar_analysis_strategy ) +if(BUILD_PHASAR_CLANG) + list(APPEND PHASAR_LINK_LIBS phasar_clang) +endif() if(SQLite3_FOUND) list(APPEND PHASAR_LINK_LIBS phasar_db) endif() diff --git a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index 1cbe6a3f6..e0d554e71 100644 --- a/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/lib/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -19,7 +19,7 @@ endif() if(PHASAR_USE_Z3) - set(ADDITIONAL_LINK_LIBS z3) + set(ADDITIONAL_LINK_LIBS ${Z3_LIBRARIES}) endif() add_phasar_library(phasar_llvm_pathsensitivity diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt new file mode 100644 index 000000000..a25a2c601 --- /dev/null +++ b/test_package/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.1) +project(phasar-PackageTest CXX C) + +find_package(phasar CONFIG REQUIRED) +find_package(nlohmann_json REQUIRED) + +add_executable(myphasartool myphasartool.cpp) +set_property(TARGET myphasartool PROPERTY CXX_STANDARD 17) +set_property(TARGET myphasartool PROPERTY EXPORT_COMPILE_COMMANDS YES) +set_property(TARGET myphasartool PROPERTY CXX_STANDARD_REQUIRED ON) +set_property(TARGET myphasartool PROPERTY CXX_EXTENSIONS OFF) + +target_link_libraries(myphasartool PUBLIC phasar::phasar nlohmann_json::nlohmann_json) diff --git a/test_package/conanfile.py b/test_package/conanfile.py new file mode 100644 index 000000000..b30306362 --- /dev/null +++ b/test_package/conanfile.py @@ -0,0 +1,26 @@ +import os + +from conan import ConanFile +from conan.tools.cmake import CMake, cmake_layout +from conan.tools.build import can_run + +class PhasarTestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps", "CMakeToolchain" + + def requirements(self): + self.requires(self.tested_reference_str) + self.requires("nlohmann_json/3.11.3") + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def layout(self): + cmake_layout(self) + + def test(self): + if can_run(self): + example = os.path.join(os.path.dirname(__file__), 'example.ll') + self.run(f"./myphasartool \"{example}\"", cwd=self.cpp.build.bindir, env="conanrun") #env="conanrun" run_environment=True diff --git a/test_package/example.ll b/test_package/example.ll new file mode 100644 index 000000000..3ed2ea3e4 --- /dev/null +++ b/test_package/example.ll @@ -0,0 +1,170 @@ +; ModuleID = '/home/lucas/git/itst-develop/02_sa/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c' +source_filename = "/home/lucas/git/itst-develop/02_sa/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] } +%struct._IO_marker = type opaque +%struct._IO_codecvt = type opaque +%struct._IO_wide_data = type opaque + +@stdin = external dso_local global %struct._IO_FILE*, align 8 + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @fun1(i32* %v, i32 %x) #0 !dbg !10 { +entry: + %v.addr = alloca i32*, align 8 + %x.addr = alloca i32, align 4 + store i32* %v, i32** %v.addr, align 8 + call void @llvm.dbg.declare(metadata i32** %v.addr, metadata !14, metadata !DIExpression()), !dbg !15 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !16, metadata !DIExpression()), !dbg !17 + %0 = load i32, i32* %x.addr, align 4, !dbg !18 + %cmp = icmp sgt i32 %0, 10, !dbg !20 + br i1 %cmp, label %if.then, label %if.end, !dbg !21 + +if.then: ; preds = %entry + %1 = load i32*, i32** %v.addr, align 8, !dbg !22 + %2 = bitcast i32* %1 to i8*, !dbg !22 + call void @free(i8* %2) #4, !dbg !24 + br label %if.end, !dbg !25 + +if.end: ; preds = %if.then, %entry + ret void, !dbg !26 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind +declare dso_local void @free(i8*) #2 + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @main() #0 !dbg !27 { +entry: + %retval = alloca i32, align 4 + %i = alloca i32, align 4 + %b = alloca [10 x i8], align 1 + %foo = alloca i32*, align 8 + %c = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + call void @llvm.dbg.declare(metadata i32* %i, metadata !30, metadata !DIExpression()), !dbg !31 + store i32 30, i32* %i, align 4, !dbg !31 + call void @llvm.dbg.declare(metadata [10 x i8]* %b, metadata !32, metadata !DIExpression()), !dbg !37 + %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %b, i64 0, i64 0, !dbg !38 + %0 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8, !dbg !39 + %call = call i8* @fgets(i8* %arraydecay, i32 10, %struct._IO_FILE* %0), !dbg !40 + call void @llvm.dbg.declare(metadata i32** %foo, metadata !41, metadata !DIExpression()), !dbg !42 + %call1 = call noalias i8* @malloc(i64 32) #4, !dbg !43 + %1 = bitcast i8* %call1 to i32*, !dbg !44 + store i32* %1, i32** %foo, align 8, !dbg !42 + %2 = load i32*, i32** %foo, align 8, !dbg !45 + %3 = bitcast i32* %2 to i8*, !dbg !45 + call void @free(i8* %3) #4, !dbg !46 + call void @llvm.dbg.declare(metadata i32* %c, metadata !47, metadata !DIExpression()), !dbg !48 + %arraydecay2 = getelementptr inbounds [10 x i8], [10 x i8]* %b, i64 0, i64 0, !dbg !49 + %4 = ptrtoint i8* %arraydecay2 to i32, !dbg !49 + store i32 %4, i32* %c, align 4, !dbg !48 + %5 = load i32, i32* %c, align 4, !dbg !50 + %cmp = icmp sgt i32 %5, 40, !dbg !52 + br i1 %cmp, label %if.then, label %if.end, !dbg !53 + +if.then: ; preds = %entry + %6 = load i32*, i32** %foo, align 8, !dbg !54 + %7 = load i32, i32* %c, align 4, !dbg !56 + call void @fun1(i32* %6, i32 %7), !dbg !57 + br label %if.end, !dbg !58 + +if.end: ; preds = %if.then, %entry + %8 = load i32, i32* %i, align 4, !dbg !59 + %cmp3 = icmp eq i32 %8, 20, !dbg !61 + br i1 %cmp3, label %if.then4, label %if.end5, !dbg !62 + +if.then4: ; preds = %if.end + br label %if.end5, !dbg !63 + +if.end5: ; preds = %if.then4, %if.end + ret i32 0, !dbg !65 +} + +declare dso_local i8* @fgets(i8*, i32, %struct._IO_FILE*) #3 + +; Function Attrs: nounwind +declare dso_local noalias i8* @malloc(i64) #2 + +attributes #0 = { noinline nounwind optnone uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #2 = { nounwind "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git d28af7c654d8db0b68c175db5ce212d74fb5e9bc)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "/home/lucas/git/itst-develop/02_sa/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c", directory: "/home/lucas/git/itst-develop/02_sa/build/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!6 = !{i32 7, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{i32 1, !"wchar_size", i32 4} +!9 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git d28af7c654d8db0b68c175db5ce212d74fb5e9bc)"} +!10 = distinct !DISubprogram(name: "fun1", scope: !11, file: !11, line: 6, type: !12, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!11 = !DIFile(filename: "intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c", directory: "/home/lucas/git/itst-develop/02_sa") +!12 = !DISubroutineType(types: !13) +!13 = !{null, !4, !5} +!14 = !DILocalVariable(name: "v", arg: 1, scope: !10, file: !11, line: 6, type: !4) +!15 = !DILocation(line: 6, column: 16, scope: !10) +!16 = !DILocalVariable(name: "x", arg: 2, scope: !10, file: !11, line: 6, type: !5) +!17 = !DILocation(line: 6, column: 23, scope: !10) +!18 = !DILocation(line: 7, column: 9, scope: !19) +!19 = distinct !DILexicalBlock(scope: !10, file: !11, line: 7, column: 9) +!20 = !DILocation(line: 7, column: 11, scope: !19) +!21 = !DILocation(line: 7, column: 9, scope: !10) +!22 = !DILocation(line: 8, column: 14, scope: !23) +!23 = distinct !DILexicalBlock(scope: !19, file: !11, line: 7, column: 17) +!24 = !DILocation(line: 8, column: 9, scope: !23) +!25 = !DILocation(line: 9, column: 5, scope: !23) +!26 = !DILocation(line: 10, column: 1, scope: !10) +!27 = distinct !DISubprogram(name: "main", scope: !11, file: !11, line: 12, type: !28, scopeLine: 12, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!28 = !DISubroutineType(types: !29) +!29 = !{!5} +!30 = !DILocalVariable(name: "i", scope: !27, file: !11, line: 13, type: !5) +!31 = !DILocation(line: 13, column: 9, scope: !27) +!32 = !DILocalVariable(name: "b", scope: !27, file: !11, line: 14, type: !33) +!33 = !DICompositeType(tag: DW_TAG_array_type, baseType: !34, size: 80, elements: !35) +!34 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!35 = !{!36} +!36 = !DISubrange(count: 10) +!37 = !DILocation(line: 14, column: 10, scope: !27) +!38 = !DILocation(line: 15, column: 11, scope: !27) +!39 = !DILocation(line: 15, column: 18, scope: !27) +!40 = !DILocation(line: 15, column: 5, scope: !27) +!41 = !DILocalVariable(name: "foo", scope: !27, file: !11, line: 16, type: !4) +!42 = !DILocation(line: 16, column: 10, scope: !27) +!43 = !DILocation(line: 16, column: 23, scope: !27) +!44 = !DILocation(line: 16, column: 16, scope: !27) +!45 = !DILocation(line: 17, column: 10, scope: !27) +!46 = !DILocation(line: 17, column: 5, scope: !27) +!47 = !DILocalVariable(name: "c", scope: !27, file: !11, line: 18, type: !5) +!48 = !DILocation(line: 18, column: 9, scope: !27) +!49 = !DILocation(line: 18, column: 13, scope: !27) +!50 = !DILocation(line: 19, column: 9, scope: !51) +!51 = distinct !DILexicalBlock(scope: !27, file: !11, line: 19, column: 9) +!52 = !DILocation(line: 19, column: 11, scope: !51) +!53 = !DILocation(line: 19, column: 9, scope: !27) +!54 = !DILocation(line: 20, column: 14, scope: !55) +!55 = distinct !DILexicalBlock(scope: !51, file: !11, line: 19, column: 17) +!56 = !DILocation(line: 20, column: 19, scope: !55) +!57 = !DILocation(line: 20, column: 9, scope: !55) +!58 = !DILocation(line: 21, column: 5, scope: !55) +!59 = !DILocation(line: 23, column: 9, scope: !60) +!60 = distinct !DILexicalBlock(scope: !27, file: !11, line: 23, column: 9) +!61 = !DILocation(line: 23, column: 11, scope: !60) +!62 = !DILocation(line: 23, column: 9, scope: !27) +!63 = !DILocation(line: 25, column: 5, scope: !64) +!64 = distinct !DILexicalBlock(scope: !60, file: !11, line: 23, column: 18) +!65 = !DILocation(line: 26, column: 5, scope: !27) diff --git a/test_package/myphasartool.cpp b/test_package/myphasartool.cpp new file mode 100644 index 000000000..f95f34ce2 --- /dev/null +++ b/test_package/myphasartool.cpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright (c) 2017 Philipp Schubert. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Philipp Schubert and others + *****************************************************************************/ + +#include "phasar.h" + +#include +#include + +using namespace psr; + +int main(int Argc, const char **Argv) { + using namespace std::string_literals; + + if (Argc < 2 || !std::filesystem::exists(Argv[1]) || + std::filesystem::is_directory(Argv[1])) { + llvm::errs() << "myphasartool\n" + "A small PhASAR-based example program\n\n" + "Usage: myphasartool \n"; + return 1; + } + + std::vector EntryPoints = {"main"s}; + + HelperAnalyses HA(Argv[1], EntryPoints); + + if (const auto *F = HA.getProjectIRDB().getFunctionDefinition("main")) { + // print type hierarchy + HA.getTypeHierarchy().print(); + // print points-to information + HA.getAliasInfo().print(); + // print inter-procedural control-flow graph + HA.getICFG().print(); + + // IFDS template parametrization test + llvm::outs() << "Testing IFDS:\n"; + auto L = createAnalysisProblem(HA, EntryPoints); + IFDSSolver S(L, &HA.getICFG()); + auto IFDSResults = S.solve(); + IFDSResults.dumpResults(HA.getICFG()); + + // IDE template parametrization test + llvm::outs() << "Testing IDE:\n"; + auto M = createAnalysisProblem(HA, EntryPoints); + // Alternative way of solving an IFDS/IDEProblem: + auto IDEResults = solveIDEProblem(M, HA.getICFG()); + IDEResults.dumpResults(HA.getICFG()); + + } else { + llvm::errs() << "error: file does not contain a 'main' function!\n"; + } + return 0; +} diff --git a/test_package/test.sh b/test_package/test.sh new file mode 100755 index 000000000..917d0f714 --- /dev/null +++ b/test_package/test.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -euo pipefail + +( + cd "$(dirname "$0")/.." + conan create -o "phasar/*:unittests=False" . +) diff --git a/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt index ac70e1b3e..11f6cc1e5 100644 --- a/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt +++ b/unittests/PhasarLLVM/DataFlow/PathSensitivity/CMakeLists.txt @@ -4,6 +4,6 @@ if(PHASAR_USE_Z3) target_link_libraries(PathTracingTest LINK_PUBLIC phasar_llvm_pathsensitivity - z3 + ${Z3_LIBRARIES} ) endif() diff --git a/utils/conan/clang/14x/0000-force-import-original-llvm-config.patch b/utils/conan/clang/14x/0000-force-import-original-llvm-config.patch new file mode 100644 index 000000000..3d83df819 --- /dev/null +++ b/utils/conan/clang/14x/0000-force-import-original-llvm-config.patch @@ -0,0 +1,12 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 937a8467df1d..c3550d863ad9 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -70,6 +70,7 @@ if(CLANG_BUILT_STANDALONE) + mark_as_advanced(LLVM_ENABLE_ASSERTIONS) + endif() + ++ include(LLVMConfig.original) + find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}") + list(APPEND CMAKE_MODULE_PATH "${LLVM_DIR}") + diff --git a/utils/conan/clang/conandata.yml b/utils/conan/clang/conandata.yml new file mode 100644 index 000000000..dcca509be --- /dev/null +++ b/utils/conan/clang/conandata.yml @@ -0,0 +1,12 @@ +sources: + "18.1.7": + url: https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.7/clang-18.1.7.src.tar.xz + sha256: c9191e4896e43425a8fbbb29e3b25b3a83050781809fbd4d0ad2382bc4a5c43d + "14.0.6": + url: https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/clang-14.0.6.src.tar.xz + sha256: 2b5847b6a63118b9efe5c85548363c81ffe096b66c3b3675e953e26342ae4031 +patches: + "14.0.6": + - patch_file: patches/14x/0000-force-import-original-llvm-config.patch + patch_description: Imports definitions from original LLVMConfig + patch_type: conan diff --git a/utils/conan/clang/conanfile.py b/utils/conan/clang/conanfile.py new file mode 100644 index 000000000..c1c0132c4 --- /dev/null +++ b/utils/conan/clang/conanfile.py @@ -0,0 +1,281 @@ +import json +import re +import textwrap +from pathlib import Path + +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.env import VirtualBuildEnv +from conan.tools.files import ( + apply_conandata_patches, + copy, + export_conandata_patches, + get, + collect_libs, + replace_in_file, + rm, + rmdir, + save, + load, + rename +) +from conan.tools.microsoft import check_min_vs, is_msvc, is_msvc_static_runtime +from conan.tools.scm import Version +from os.path import join + + +required_conan_version = ">=2.0" + +class ClangConan(ConanFile): + name = "clang" + description = "The Clang project provides a language front-end and tooling infrastructure for languages in the C language family" + license = "Apache-2 with LLVM-exception" + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://clang.llvm.org/" + topics = ("clang", "llvm", "compiler") + package_type = "library" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "with_xml2": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + "with_xml2": True # LLVM_ENABLE_LIBXML2 + } + + @property + def _min_cppstd(self): + return 17 + + @property + def _compilers_minimum_version(self): + return { + "apple-clang": "10", + "clang": "7", + "gcc": "7", + "msvc": "191", + "Visual Studio": "15", + } + + def export_sources(self): + export_conandata_patches(self) + + def layout(self): + cmake_layout(self, src_folder="src") + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def build_requirements(self): + self.tool_requires("ninja/[>=1.10.2 <2]") + # needed to build c-index-test but not actually required by any components + if self.options.with_xml2: + # 2.5.3 min required by llvm 14 + self.test_requires("libxml2/[>=2.5.3 <3]") + + def requirements(self): + self.requires(f"llvm-core/{self.version}", transitive_headers=True, transitive_libs=True) + + def validate(self): + if self.settings.compiler.cppstd: + check_min_cppstd(self, self._min_cppstd) + minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False) + if minimum_version and Version(self.settings.compiler.version) < minimum_version: + raise ConanInvalidConfiguration( + f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support." + ) + + def source(self): + get(self, **self.conan_data["sources"][self.version]) + + clang_folder=f"clang-{self.version}.src" + rename(self, "cmake/Modules", "cmake/modules") + copy(self, pattern="*", src=clang_folder, dst=".") + rmdir(self, clang_folder) + + @property + def _get_llvm_path(self): + return Path(self.dependencies["llvm-core"].package_folder).resolve().as_posix() + + def generate(self): + cmake_tc = CMakeToolchain(self, generator="Ninja") + cmake_variables = { + "CMAKE_MODULE_PATH": join(self._get_llvm_path, "lib", "cmake", "llvm"), + # "LLVM_TOOLS_INSTALL_DIR": "bin", + # "LLVM_INCLUDE_TESTS": False, + "CLANG_INCLUDE_DOCS": False, + } + cmake_tc.cache_variables.update(cmake_variables) + cmake_tc.generate() + + cmake_deps = CMakeDeps(self) + cmake_deps.generate() + + def build(self): + apply_conandata_patches(self) + cmake = CMake(self) + cmake.configure(cli_args=['--graphviz=graph/clang.dot']) + cmake.build() + + def _clang_build_info(self): + def _sanitized_components(dependencies): + is_link_only = re.compile(r"""\\\$""") + + # CMake Target package::component -> Conan package::component + replacements = { + "LibXml2::LibXml2": "libxml2::libxml2", + } + for dep in dependencies.split(";"): + match = is_link_only.search(dep) + if match: + yield match.group(1) + else: + replacement = replacements.get(dep) + if replacement: + yield replacement + elif dep.startswith("-l"): + yield dep[2:] + elif dep.startswith("LLVM"): + yield f"llvm-core::{dep}" + else: + yield dep + + def _parse_deps(deps): + data = { + "requires": [], + "system_libs": [], + } + windows_system_libs = [ + "ole32", + "delayimp", + "shell32", + "advapi32", + "-delayload:shell32.dll", + "uuid", + "psapi", + "-delayload:ole32.dll" + ] + for component in _sanitized_components(deps): + if component in windows_system_libs: + continue + if component in ["rt", "m", "dl", "pthread"]: + data["system_libs"].append(component) + else: + data["requires"].append(component) + return data + + targets = load(self, self.package_folder / self._cmake_module_path / "ClangTargets.cmake") + + match_libraries = re.compile(r'''^add_library\((\S+).*\)$''', re.MULTILINE) + libraries = set(match_libraries.findall(targets)) + + match_dependencies = re.compile( + r'''^set_target_properties\((\S+).*\n?\s*INTERFACE_LINK_LIBRARIES\s+"(\S+)"''', re.MULTILINE) + + components = {} + for component, dependencies in match_dependencies.findall(targets): + if component in libraries: + if component in components: + components[component].update(_parse_deps(dependencies)) + else: + components[component] = _parse_deps(dependencies) + return components + + @property + def _cmake_module_path(self): + return Path("lib") / "cmake" / "clang" + + @property + def _build_module_file(self): + return self._cmake_module_path / f"conan-official-{self.name}-variables.cmake" + + @property + def _components_path(self): + return Path(self.package_folder) / self._cmake_module_path / "components.json" + + def _create_cmake_build_module(self, module_file): + package_folder = Path(self.package_folder) + content = textwrap.dedent(f"""\ + set(CLANG_INSTALL_PREFIX "{str(package_folder)}") + set(CLANG_CMAKE_DIR "{str(package_folder / self._cmake_module_path)}") + if (NOT TARGET clang-tablegen-targets) + add_custom_target(clang-tablegen-targets) + endif() + list(APPEND CMAKE_MODULE_PATH "${{LLVM_CMAKE_DIR}}") + # should have been be included by AddClang but isn't + include(AddLLVM) + """) + save(self, module_file, content) + + def _write_build_info(self): + components = self._clang_build_info() + with open(self._components_path, "w", encoding="utf-8") as fp: + json.dump(components, fp) + + def _read_build_info(self): + with open(self._components_path, "r", encoding="utf-8") as fp: + return json.load(fp) + + def package(self): + copy(self, "LICENSE.TXT", self.source_folder, join(self.package_folder, "licenses")) + cmake = CMake(self) + cmake.install() + + self._write_build_info() + package_folder = Path(self.package_folder) + self._create_cmake_build_module(package_folder / self._build_module_file) + + cmake_folder = package_folder / self._cmake_module_path + rm(self, "ClangConfig*", cmake_folder) + rm(self, "ClangTargets*", cmake_folder) + rmdir(self, package_folder / "share") + + def package_info(self): + def _add_no_rtti_flag(component): + if is_msvc(self): + component.cxxflags.append("/GS-") + else: + component.cxxflags.append("-fno-rtti") + + # def _lib_name_from_component(name): + # replacements = { + # "libclang": "clang" + # } + # return replacements.get(name, name) + + self.cpp_info.set_property("cmake_file_name", "Clang") + self.cpp_info.set_property("cmake_build_modules", + [self._build_module_file, + self._cmake_module_path / "AddClang.cmake"] + ) + + self.cpp_info.builddirs.append(self._cmake_module_path) + + llvm = self.dependencies["llvm-core"] + if not llvm.options.rtti: + _add_no_rtti_flag(self.cpp_info) + + if not self.options.shared: + components = self._read_build_info() + for component_name, data in components.items(): + self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) + self.cpp_info.components[component_name].libs = [component_name] + if data["requires"] is not None: + self.cpp_info.components[component_name].requires += data["requires"] + if data["system_libs"] is not None: + self.cpp_info.components[component_name].system_libs += data["system_libs"] + if not llvm.options.rtti: + _add_no_rtti_flag(self.cpp_info.components[component_name]) + else: + self.cpp_info.set_property("cmake_target_name", "Clang") + self.cpp_info.libs = collect_libs(self) diff --git a/utils/conan/clang/test_package/CMakeLists.txt b/utils/conan/clang/test_package/CMakeLists.txt new file mode 100644 index 000000000..87e796911 --- /dev/null +++ b/utils/conan/clang/test_package/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.15) + +project(test_package LANGUAGES CXX) + +#if (NOT LLVM_HAS_RTTI) +# if (MSVC) +# string(APPEND CMAKE_CXX_FLAGS " -fno-rtti") +# else() +#endif() +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frtti") + +find_package(Clang REQUIRED COMPONENTS clangTooling) + +add_executable(${PROJECT_NAME} test_package.cpp) +target_link_libraries(${PROJECT_NAME} PRIVATE clangTooling) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) diff --git a/utils/conan/clang/test_package/conanfile.py b/utils/conan/clang/test_package/conanfile.py new file mode 100644 index 000000000..a576a5655 --- /dev/null +++ b/utils/conan/clang/test_package/conanfile.py @@ -0,0 +1,38 @@ +from io import StringIO + +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import cmake_layout, CMake +import os + +class TestPackageConan(ConanFile): + settings = "os", "arch", "compiler", "build_type" + test_type = "explicit" + generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv" + + def requirements(self): + self.requires(self.tested_reference_str, run=True) + + def layout(self): + cmake_layout(self) + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def _test_libtooling(self): + bin_path = os.path.join(self.cpp.build.bindir, "test_package") + self.run(f"{bin_path} --help" , env="conanrun") + + def _test_clang(self): + clang = self.dependencies["clang"] + clang_path = os.path.join(clang.package_folder, "bin", "clang") + output = StringIO() + self.run("which clang", env="conanrun", stdout=output) + assert clang_path in output.getvalue().splitlines() + + def test(self): + if can_run(self): + self._test_libtooling() + self._test_clang() diff --git a/utils/conan/clang/test_package/test_package.cpp b/utils/conan/clang/test_package/test_package.cpp new file mode 100644 index 000000000..361050c0d --- /dev/null +++ b/utils/conan/clang/test_package/test_package.cpp @@ -0,0 +1,35 @@ +// A basic clang libtooling example from https://clang.llvm.org/docs/LibTooling.html + +// Declares clang::SyntaxOnlyAction. +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" +// Declares llvm::cl::extrahelp. +#include "llvm/Support/CommandLine.h" + +using namespace clang::tooling; +using namespace llvm; + +// Apply a custom category to all command-line options so that they are the +// only ones displayed. +static cl::OptionCategory MyToolCategory("my-tool options"); + +// CommonOptionsParser declares HelpMessage with a description of the common +// command-line options related to the compilation database and input files. +// It's nice to have this help message in all tools. +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); + +// A help message for this specific tool can be added afterwards. +static cl::extrahelp MoreHelp("\nMore help text...\n"); + +int main(int argc, const char **argv) { + auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory); + if (!ExpectedParser) { + llvm::errs() << ExpectedParser.takeError(); + return 1; + } + CommonOptionsParser& OptionsParser = ExpectedParser.get(); + ClangTool Tool(OptionsParser.getCompilations(), + OptionsParser.getSourcePathList()); + return Tool.run(newFrontendActionFactory().get()); +} diff --git a/utils/conan/llvm-core/all/conandata.yml b/utils/conan/llvm-core/all/conandata.yml new file mode 100644 index 000000000..2d1054c18 --- /dev/null +++ b/utils/conan/llvm-core/all/conandata.yml @@ -0,0 +1,25 @@ +sources: + "14.0.6": + url: https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/llvm-14.0.6.src.tar.xz + sha256: 050922ecaaca5781fdf6631ea92bc715183f202f9d2f15147226f023414f619a + +patches: + "14.0.6": + - patch_file: patches/14x/0000-cmake-dependencies.patch + patch_description: fix references to third party libs to match conan variables and targets + patch_type: conan + - patch_file: patches/14x/0001-calculate-job-pools.patch + patch_description: calculate resource limits for compiling LLVM + patch_type: portability + patch_source: https://github.com/llvm/llvm-project/pull/65274 + - patch_file: patches/14x/0002-missing-includes.patch + patch_description: fix missing header files + patch_type: portability + patch_source: https://github.com/llvm/llvm-project-release-prs/pull/3 + - patch_file: patches/14x/0003-no-build-with-install-rpath.patch + patch_description: do not build shared libs with install rpath + patch_type: conan + - patch_file: patches/14x/0004-remove-lto-exports.patch + patch_description: remove LTO exports causing link error with lld + patch_source: https://github.com/llvm/llvm-project-release-prs/pull/279 + patch_type: portability diff --git a/utils/conan/llvm-core/all/conanfile.py b/utils/conan/llvm-core/all/conanfile.py new file mode 100644 index 000000000..119832b8e --- /dev/null +++ b/utils/conan/llvm-core/all/conanfile.py @@ -0,0 +1,507 @@ +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.apple import is_apple_os +from conan.tools.build import check_min_cppstd, cross_building +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import ( + apply_conandata_patches, + collect_libs, + get, + rmdir, + save, + copy, + export_conandata_patches, + rm, + rename, + replace_in_file +) +from conan.tools.microsoft import is_msvc, msvc_runtime_flag +from conan.tools.scm import Version + +import json +from os import getenv +from os.path import join +from pathlib import Path +import re +import textwrap + + +required_conan_version = ">=1.62.0" + +# LLVM's default config is to enable all targets, but end users can significantly reduce +# build times for the package by specifying only the targets they need as a +# semi-colon delimited string in the value of the 'targets' option +LLVM_TARGETS = { + "AArch64", + "AMDGPU", + "ARM", + "AVR", + "BPF", + "Hexagon", + "Lanai", + "Mips", + "MSP430", + "NVPTX", + "PowerPC", + "RISCV", + "Sparc", + "SystemZ", + "WebAssembly", + "X86", + "XCore" +} + + +class LLVMCoreConan(ConanFile): + name = "llvm-core" + description = ( + "A toolkit for the construction of highly optimized compilers," + "optimizers, and runtime environments." + ) + license = "Apache-2.0 WITH LLVM-exception" + topics = ("llvm", "compiler") + homepage = "https://llvm.org" + url = "https://github.com/conan-io/conan-center-index" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "components": ["ANY"], + "targets": ["ANY"], + "exceptions": [True, False], + "rtti": [True, False], + "threads": [True, False], + "lto": ["On", "Off", "Full", "Thin"], + "static_stdlib": [True, False], + "unwind_tables": [True, False], + "expensive_checks": [True, False], + "use_perf": [True, False], + "use_sanitizer": [ + "Address", + "Memory", + "MemoryWithOrigins", + "Undefined", + "Thread", + "DataFlow", + "Address;Undefined", + "None" + ], + "with_curl": [True, False], + "with_ffi": [True, False], + "with_libedit": [True, False], + "with_terminfo": [True, False], + "with_zlib": [True, False], + "with_xml2": [True, False], + "with_z3": [True, False], + } + default_options = { + "shared": False, + "fPIC": True, + "components": "all", + "targets": "all", + "exceptions": True, + "rtti": True, + "threads": True, + "lto": "Off", + "static_stdlib": False, + "unwind_tables": True, + "expensive_checks": False, + "use_perf": False, + "use_sanitizer": "None", + "with_curl": True, + "with_libedit": True, + "with_ffi": False, + "with_terminfo": False, # differs from LLVM default + "with_xml2": True, + "with_z3": True, # not default + "with_zlib": True, + } + + @property + def _min_cppstd(self): + return 14 + + @property + def _compilers_minimum_version(self): + return { + "apple-clang": "10", + "clang": "7", + "gcc": "7", + "msvc": "191", + "Visual Studio": "15", + } + + def export_sources(self): + export_conandata_patches(self) + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + del self.options.with_libedit # not supported on windows + + release = Version(self.version).major + if release < 14: + del self.options.with_curl + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self, src_folder="src") + + def requirements(self): + # min version taken from llvm < conancenter v2 min < working + if self.options.with_ffi: + self.requires("libffi/[>=3.3 <4]") # no version required llvm 11-19 + if self.options.get_safe("with_libedit"): + self.requires("editline/3.1") # no version required llvm 11-19 + if self.options.with_zlib: + self.requires("zlib/[>=1.2.11 <2]") # no version required llvm 11-19 + if self.options.with_xml2: + self.requires("libxml2/[>=2.9.10 <3]") # no version required llvm 11-19 + if self.options.with_z3: + self.requires("z3/[>=4.9.1 <5]") # llvm 11-18 4.8.9, 19 4.8.9 + if self.options.get_safe("with_curl"): + self.requires('libcurl/[>=7.78.0 <9]') # no version requirement in llvm 14-19 + if self.options.get_safe("with_zstd"): + self.requires("zstd/[>=1.4.3 <2]") # no version required llvm 15-19, <1.4.3 doesn't work + + def build_requirements(self): + self.tool_requires("ninja/[>=1.10.2 <2]") + + def validate(self): + if self.settings.compiler.cppstd: + check_min_cppstd(self, self._min_cppstd) + minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False) + if minimum_version and Version(self.settings.compiler.version) < minimum_version: + raise ConanInvalidConfiguration( + f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support." + ) + + if self.options.shared: + if self.settings.os == "Windows": + raise ConanInvalidConfiguration("Shared builds are currently not supported on Windows") + if is_apple_os(self): + # FIXME iconv contains duplicate symbols in the libiconv and libcharset libraries (both of which are + # provided by libiconv). This may be an issue with how conan packages libiconv + iconv_dep = self.dependencies.get("libiconv") + if iconv_dep and not iconv_dep.options.shared: + raise ConanInvalidConfiguration("Static iconv cannot be linked into a shared library on macos " + "due to duplicate symbols. Use libxml2/*:iconv=False.") + + if self.options.exceptions and not self.options.rtti: + raise ConanInvalidConfiguration("Cannot enable exceptions without rtti support") + + if cross_building(self): + # FIXME support cross compilation + # For Cross Building, LLVM builds a "native" toolchain in a subdirectory of the main build directory. + # This subdirectory would need to have the conan cmake configuration files for the build platform + # installed into it for a cross build to be successful. + # see also https://llvm.org/docs/HowToCrossCompileLLVM.html + raise ConanInvalidConfiguration("Cross compilation is not supported. Contributions are welcome!") + + def validate_build(self): + if getenv("CONAN_CENTER_BUILD_SERVICE") and self.settings.build_type == "Debug": + if self.settings.os == "Linux": + raise ConanInvalidConfiguration("Debug build is not supported on CCI due to resource limitations") + elif self.options.shared: + raise ConanInvalidConfiguration("Shared Debug build is not supported on CCI due to resource limitations") + + def source(self): + get(self, **self.conan_data["sources"][self.version]) + + llvm_folder=f"llvm-{self.version}.src" + rename(self, "cmake/Modules", "cmake/modules") + copy(self, pattern="*", src=llvm_folder, dst=".") + rmdir(self, llvm_folder) + + def _apply_resource_limits(self, cmake_definitions): + if getenv("CONAN_CENTER_BUILD_SERVICE"): + self.output.info("Applying CCI Resource Limits") + default_ram_per_compile_job = 16384 + default_ram_per_link_job = 2048 + else: + default_ram_per_compile_job = None + default_ram_per_link_job = None + + ram_per_compile_job = self.conf.get("user.llvm-core:ram_per_compile_job", default_ram_per_compile_job) + if ram_per_compile_job: + cmake_definitions["LLVM_RAM_PER_COMPILE_JOB"] = ram_per_compile_job + + ram_per_link_job = self.conf.get("user.llvm-core:ram_per_link_job", default_ram_per_link_job) + if ram_per_link_job: + cmake_definitions["LLVM_RAM_PER_LINK_JOB"] = ram_per_link_job + + @property + def _targets_to_build(self): + return self.options.targets if self.options.targets != "all" else self._all_targets + + @property + def _all_targets(self): + targets = LLVM_TARGETS + ver = Version(self.version).major + if ver >= 14: + targets.add("VE") + if ver >= 15: + targets.add("LoongArch") + return ";".join(targets) + + def generate(self): + tc = CMakeToolchain(self, generator="Ninja") + # https://releases.llvm.org/12.0.0/docs/CMake.html + # https://releases.llvm.org/13.0.0/docs/CMake.html + # https://releases.llvm.org/14.0.0/docs/CMake.html + cmake_variables = { + # Enables LLVM to find conan libraries during try_compile + "CMAKE_TRY_COMPILE_CONFIGURATION": str(self.settings.build_type), + # LLVM has two separate concepts of a "shared library build". + # "BUILD_SHARED_LIBS" builds shared versions of all the static components + # "LLVM_BUILD_LLVM_DYLIB" builds a single shared library containing all components. + # It is likely the latter that the user expects by a "shared library" build. + "BUILD_SHARED_LIBS": False, + "LLVM_BUILD_LLVM_DYLIB": self.options.shared, + "LLVM_LINK_LLVM_DYLIB": self.options.shared, + "LLVM_DYLIB_COMPONENTS": self.options.components, + "LLVM_ABI_BREAKING_CHECKS": "WITH_ASSERTS", + "LLVM_INCLUDE_BENCHMARKS": False, + "LLVM_INCLUDE_TOOLS": True, + "LLVM_INCLUDE_EXAMPLES": False, + "LLVM_INCLUDE_TESTS": False, + "LLVM_ENABLE_IDE": False, + "LLVM_ENABLE_EH": self.options.exceptions, + "LLVM_ENABLE_RTTI": self.options.rtti, + "LLVM_ENABLE_THREADS": self.options.threads, + "LLVM_ENABLE_LTO": self.options.lto, + "LLVM_STATIC_LINK_CXX_STDLIB": self.options.static_stdlib, + "LLVM_ENABLE_UNWIND_TABLES": self.options.unwind_tables, + "LLVM_ENABLE_EXPENSIVE_CHECKS": self.options.expensive_checks, + "LLVM_ENABLE_ASSERTIONS": str(self.settings.build_type) == 'Debug', + "LLVM_USE_PERF": self.options.use_perf, + 'LLVM_ENABLE_CURL': 'FORCE_ON' if self.options.get_safe('with_curl', False) else False, + "LLVM_ENABLE_LIBEDIT": self.options.get_safe("with_libedit", False), + "LLVM_ENABLE_Z3_SOLVER": self.options.with_z3, + "LLVM_ENABLE_FFI": self.options.with_ffi, + "LLVM_ENABLE_ZLIB": "FORCE_ON" if self.options.with_zlib else False, + "LLVM_ENABLE_LIBXML2": "FORCE_ON" if self.options.with_xml2 else False, + "LLVM_ENABLE_TERMINFO": self.options.with_terminfo + } + if self.options.targets != "all": + cmake_variables["LLVM_TARGETS_TO_BUILD"] = self.options.targets + + self._apply_resource_limits(cmake_variables) + + if is_msvc(self): + build_type = str(self.settings.build_type).upper() + cmake_variables[f"LLVM_USE_CRT_{build_type}"] = msvc_runtime_flag(self) + + if not self.options.shared: + cmake_variables.update({ + "DISABLE_LLVM_LINK_LLVM_DYLIB": True, + "LLVM_ENABLE_PIC": self.options.get_safe("fPIC", default=True) + }) + + if self.options.use_sanitizer == "None": + cmake_variables["LLVM_USE_SANITIZER"] = "" + else: + cmake_variables["LLVM_USE_SANITIZER"] = self.options.use_sanitizer + + if self.settings.os == "Linux": + # Workaround for: https://github.com/conan-io/conan/issues/13560 + libdirs_host = [l for dependency in self.dependencies.host.values() for l in dependency.cpp_info.aggregated_components().libdirs] + tc.variables["CMAKE_BUILD_RPATH"] = ";".join(libdirs_host) + + tc.cache_variables.update(cmake_variables) + tc.generate() + + tc = CMakeDeps(self) + tc.generate() + + def build(self): + apply_conandata_patches(self) + cmake = CMake(self) + cmake.configure() + cmake.build() + + @property + def _package_folder_path(self): + return Path(self.package_folder) + + def _update_component_dependencies(self, components): + def _sanitized_components(deps_list): + match_genex = re.compile(r"""\\\$""") + # CMake Target package::component -> Conan package::component + replacements = { + "LibXml2::LibXml2": "libxml2::libxml2", + "ZLIB::ZLIB": "zlib::zlib", + "CURL::libcurl": "libcurl::libcurl" + } + for dep in deps_list.split(";"): + match = match_genex.search(dep) + if match: + yield match.group(1) + else: + replacement = replacements.get(dep) + if replacement: + yield replacement + elif dep.startswith("-l"): + yield dep[2:] + else: + yield dep + + def _parse_deps(deps_list): + data = { + "requires": [], + "system_libs": [] + } + windows_system_libs = [ + "ole32", + "delayimp", + "shell32", + "advapi32", + "-delayload:shell32.dll", + "uuid", + "psapi", + "-delayload:ole32.dll" + ] + for component in _sanitized_components(deps_list): + if component in windows_system_libs: + continue + if component in ["rt", "m", "dl", "pthread"]: + data["system_libs"].append(component) + else: + data["requires"].append(component) + return data + + # Can't use tools.files.load due to CRLF endings on Windows causing issues with Regular Expressions + cmake_exports = (self._package_folder_path / "lib" / "cmake" / "llvm" / "LLVMExports.cmake").read_text("utf-8") + match_dependencies = re.compile( + r'''^set_target_properties\((\w+).*\n?\s*INTERFACE_LINK_LIBRARIES\s+"(\S+)"''', re.MULTILINE) + + for llvm_lib, dependencies in match_dependencies.findall(cmake_exports): + if llvm_lib in components: + components[llvm_lib].update(_parse_deps(dependencies)) + + def _llvm_build_info(self): + cmake_config = (self._package_folder_path / "lib" / "cmake" / "llvm" / "LLVMConfig.cmake").read_text("utf-8") + + match_cmake_var = re.compile(r"""^set\(LLVM_AVAILABLE_LIBS (?P.*)\)$""", re.MULTILINE) + match = match_cmake_var.search(cmake_config) + if match is None: + self.output.warning("Could not find components in LLVMConfig.cmake") + return None + + components = {component: {} for component in match.groupdict()["components"].split(";")} + self._update_component_dependencies(components) + + return { + "components": components, + "native_arch": re.search(r"""^set\(LLVM_NATIVE_ARCH (\S*)\)$""", cmake_config, re.MULTILINE).group(1) + } + + @property + def _cmake_module_path(self): + return Path("lib") / "cmake" / "llvm" + + @property + def _build_info_file(self): + return self._package_folder_path / self._cmake_module_path / "conan_llvm_build_info.json" + + @property + def _build_module_file_rel_path(self): + return self._cmake_module_path / f"conan-official-{self.name}-variables.cmake" + + def _create_cmake_build_module(self, build_info, module_file): + targets_with_jit = ["X86", "PowerPC", "AArch64", "ARM", "Mips", "SystemZ"] + content = textwrap.dedent(f"""\ + set(LLVM_TOOLS_BINARY_DIR "${{CMAKE_CURRENT_LIST_DIR}}/../../../bin") + cmake_path(NORMAL_PATH LLVM_TOOLS_BINARY_DIR) + set(LLVM_PACKAGE_VERSION "{self.version}") + set(LLVM_AVAILABLE_LIBS "{';'.join(build_info['components'].keys())}") + set(LLVM_BUILD_TYPE "{self.settings.build_type}") + set(LLVM_CMAKE_DIR "${{CMAKE_CURRENT_LIST_DIR}}") + set(LLVM_ALL_TARGETS "{self._all_targets}") + set(LLVM_TARGETS_TO_BUILD "{self._targets_to_build}") + set(LLVM_TARGETS_WITH_JIT "{';'.join(targets_with_jit)}") + set(LLVM_NATIVE_ARCH "{build_info['native_arch']}") + set_property(GLOBAL PROPERTY LLVM_TARGETS_CONFIGURED On) + set_property(GLOBAL PROPERTY LLVM_COMPONENT_LIBS ${{LLVM_AVAILABLE_LIBS}}) + if (NOT TARGET intrinsics_gen) + add_custom_target(intrinsics_gen) + endif() + if (NOT TARGET omp_gen) + add_custom_target(omp_gen) + endif() + if (NOT TARGET acc_gen) + add_custom_target(acc_gen) + endif() + """) + save(self, module_file, content) + + def _write_build_info(self): + build_info = self._llvm_build_info() + with open(self._build_info_file, "w", encoding="utf-8") as fp: + json.dump(build_info, fp, indent=2) + + return build_info + + def _read_build_info(self) -> dict: + with open(self._build_info_file, encoding="utf-8") as fp: + return json.load(fp) + + def package(self): + copy(self, "LICENSE.TXT", self.source_folder, (self._package_folder_path / "licenses").as_posix()) + cmake = CMake(self) + cmake.install() + + build_info = self._write_build_info() + + cmake_folder = self._package_folder_path / "lib" / "cmake" / "llvm" + cmake_folder_posix = cmake_folder.as_posix() + # Variables from this file are expected by other LLVM packages + llvm_config_original = join(cmake_folder_posix, "LLVMConfig.original.cmake") + rename(self, join(cmake_folder_posix, "LLVMConfig.cmake"), llvm_config_original) + # don't include LLVMExports.cmake / LLVM-Config.cmake + replace_in_file(self, llvm_config_original, "include(", "#include(") + + rm(self, "LLVMExports*", cmake_folder_posix) + rm(self, "Find*", cmake_folder_posix) + rm(self, "*.pdb", (self._package_folder_path / "lib").as_posix()) + rm(self, "*.pdb", (self._package_folder_path / "bin").as_posix()) + # need to rename this as Conan will flag it, but it's not actually a Config file and is needed by + # downstream packages + rename(self, (cmake_folder / "LLVM-Config.cmake").as_posix(), (cmake_folder / "LLVM-ConfigInternal.cmake").as_posix()) + replace_in_file(self, (cmake_folder / "AddLLVM.cmake").as_posix(), "LLVM-Config", "LLVM-ConfigInternal") + rmdir(self, (self._package_folder_path / "share").as_posix()) + if self.options.shared: + rm(self, "*.a", (self._package_folder_path / "lib").as_posix()) + + self._create_cmake_build_module( + build_info, + (self._package_folder_path / self._build_module_file_rel_path).as_posix() + ) + + def package_info(self): + self.cpp_info.set_property("cmake_file_name", "LLVM") + self.cpp_info.set_property("cmake_build_modules", + [self._build_module_file_rel_path, + (self._cmake_module_path / "LLVM-ConfigInternal.cmake").as_posix()] + ) + self.cpp_info.builddirs.append(self._cmake_module_path) + + if not self.options.shared: + build_info = self._read_build_info() + components = build_info["components"] + + for component_name, data in components.items(): + self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) + self.cpp_info.components[component_name].libs = [component_name] + requires = data.get("requires") + if requires is not None: + self.cpp_info.components[component_name].requires += requires + system_libs = data.get("system_libs") + if system_libs is not None: + self.cpp_info.components[component_name].system_libs += system_libs + else: + self.cpp_info.set_property("cmake_target_name", "LLVM") + self.cpp_info.libs = collect_libs(self) diff --git a/utils/conan/llvm-core/all/patches/14x/0000-cmake-dependencies.patch b/utils/conan/llvm-core/all/patches/14x/0000-cmake-dependencies.patch new file mode 100644 index 000000000..e609fe9af --- /dev/null +++ b/utils/conan/llvm-core/all/patches/14x/0000-cmake-dependencies.patch @@ -0,0 +1,93 @@ +diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake +index 18d78879c968..6e5bfde1c63e 100644 +--- a/cmake/config-ix.cmake ++++ b/cmake/config-ix.cmake +@@ -63,7 +63,13 @@ check_symbol_exists(FE_ALL_EXCEPT "fenv.h" HAVE_DECL_FE_ALL_EXCEPT) + check_symbol_exists(FE_INEXACT "fenv.h" HAVE_DECL_FE_INEXACT) + + check_include_file(mach/mach.h HAVE_MACH_MACH_H) +-check_include_file(histedit.h HAVE_HISTEDIT_H) ++if(LLVM_ENABLE_LIBEDIT) ++ find_package(editline REQUIRED) ++ cmake_push_check_state() ++ list(APPEND CMAKE_REQUIRED_INCLUDES ${editline_INCLUDE_DIRS}) ++ check_include_file(histedit.h HAVE_HISTEDIT_H) ++ cmake_pop_check_state() ++endif() + check_include_file(CrashReporterClient.h HAVE_CRASHREPORTERCLIENT_H) + if(APPLE) + include(CheckCSourceCompiles) +@@ -127,7 +133,7 @@ if(LLVM_ENABLE_ZLIB) + # library on a 64-bit system which would result in a link-time failure. + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) +- list(APPEND CMAKE_REQUIRED_LIBRARIES ${ZLIB_LIBRARY}) ++ list(APPEND CMAKE_REQUIRED_LIBRARIES ${ZLIB_LIBRARIES}) + check_symbol_exists(compress2 zlib.h HAVE_ZLIB) + cmake_pop_check_state() + if(LLVM_ENABLE_ZLIB STREQUAL FORCE_ON AND NOT HAVE_ZLIB) +@@ -170,7 +176,7 @@ if(LLVM_ENABLE_CURL) + # library on a 64-bit system which would result in a link-time failure. + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS}) +- list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARY}) ++ list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARIES}) + check_symbol_exists(curl_easy_init curl/curl.h HAVE_CURL) + cmake_pop_check_state() + if(LLVM_ENABLE_CURL STREQUAL FORCE_ON AND NOT HAVE_CURL) +@@ -187,7 +193,11 @@ if(NOT LLVM_USE_SANITIZER MATCHES "Memory.*") + if (NOT PURE_WINDOWS) + # Skip libedit if using ASan as it contains memory leaks. + if (LLVM_ENABLE_LIBEDIT AND HAVE_HISTEDIT_H AND NOT LLVM_USE_SANITIZER MATCHES ".*Address.*") ++ cmake_push_check_state() ++ list(APPEND CMAKE_REQUIRED_INCLUDES ${editline_INCLUDE_DIRS}) ++ list(APPEND CMAKE_REQUIRED_LIBRARIES ${editline_LIBRARIES}) + check_library_exists(edit el_init "" HAVE_LIBEDIT) ++ cmake_pop_check_state() + else() + set(HAVE_LIBEDIT 0) + endif() +diff --git a/lib/LineEditor/CMakeLists.txt b/lib/LineEditor/CMakeLists.txt +index 61328f76905a..b95d073d9725 100644 +--- a/lib/LineEditor/CMakeLists.txt ++++ b/lib/LineEditor/CMakeLists.txt +@@ -1,5 +1,5 @@ + if(HAVE_LIBEDIT) +- set(link_libs edit) ++ set(link_libs editline::editline) + endif() + + add_llvm_component_library(LLVMLineEditor +diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt +index 4d9099554192..dc52bed15218 100644 +--- a/lib/Support/CMakeLists.txt ++++ b/lib/Support/CMakeLists.txt +@@ -271,7 +271,7 @@ if(LLVM_ENABLE_ZLIB) + # CMAKE_BUILD_TYPE is only meaningful to single-configuration generators. + if(CMAKE_BUILD_TYPE) + string(TOUPPER ${CMAKE_BUILD_TYPE} build_type) +- get_property(zlib_library TARGET ZLIB::ZLIB PROPERTY LOCATION_${build_type}) ++ set(zlib_library ${ZLIB_LIBRARIES}) + endif() + if(NOT zlib_library) + get_property(zlib_library TARGET ZLIB::ZLIB PROPERTY LOCATION) +diff --git a/lib/WindowsManifest/CMakeLists.txt b/lib/WindowsManifest/CMakeLists.txt +index 8134ac8c815b..ccd772f61767 100644 +--- a/lib/WindowsManifest/CMakeLists.txt ++++ b/lib/WindowsManifest/CMakeLists.txt +@@ -21,12 +21,13 @@ add_llvm_component_library(LLVMWindowsManifest + # This block is only needed for llvm-config. When we deprecate llvm-config and + # move to using CMake export, this block can be removed. + if(LLVM_ENABLE_LIBXML2) ++ find_package(libxml2 REQUIRED CONFIG) + # CMAKE_BUILD_TYPE is only meaningful to single-configuration generators. + if(CMAKE_BUILD_TYPE) + string(TOUPPER ${CMAKE_BUILD_TYPE} build_type) +- get_property(libxml2_library TARGET LibXml2::LibXml2 PROPERTY LOCATION_${build_type}) ++ set(libxml2_library ${libxml2_LIBRARIES}) + endif() +- if(NOT zlib_library) ++ if(NOT libxml2_library) + get_property(libxml2_library TARGET LibXml2::LibXml2 PROPERTY LOCATION) + endif() + get_library_name(${libxml2_library} libxml2_library) diff --git a/utils/conan/llvm-core/all/patches/14x/0001-calculate-job-pools.patch b/utils/conan/llvm-core/all/patches/14x/0001-calculate-job-pools.patch new file mode 100644 index 000000000..65f92b7be --- /dev/null +++ b/utils/conan/llvm-core/all/patches/14x/0001-calculate-job-pools.patch @@ -0,0 +1,44 @@ +diff --git a/cmake/modules/HandleLLVMOptions.cmake b/cmake/modules/HandleLLVMOptions.cmake +index fcaa8f20bf94..81aed11f587a 100644 +--- a/cmake/modules/HandleLLVMOptions.cmake ++++ b/cmake/modules/HandleLLVMOptions.cmake +@@ -33,6 +33,21 @@ string(TOUPPER "${LLVM_ENABLE_LTO}" uppercase_LLVM_ENABLE_LTO) + # The following only works with the Ninja generator in CMake >= 3.0. + set(LLVM_PARALLEL_COMPILE_JOBS "" CACHE STRING + "Define the maximum number of concurrent compilation jobs (Ninja only).") ++if(LLVM_RAM_PER_COMPILE_JOB OR LLVM_RAM_PER_LINK_JOB) ++ cmake_host_system_information(RESULT available_physical_memory QUERY AVAILABLE_PHYSICAL_MEMORY) ++ cmake_host_system_information(RESULT number_of_logical_cores QUERY NUMBER_OF_LOGICAL_CORES) ++endif() ++if(LLVM_RAM_PER_COMPILE_JOB) ++ math(EXPR jobs_with_sufficient_memory "${available_physical_memory} / ${LLVM_RAM_PER_COMPILE_JOB}" OUTPUT_FORMAT DECIMAL) ++ if (jobs_with_sufficient_memory LESS 1) ++ set(jobs_with_sufficient_memory 1) ++ endif() ++ if (jobs_with_sufficient_memory LESS number_of_logical_cores) ++ set(LLVM_PARALLEL_COMPILE_JOBS "${jobs_with_sufficient_memory}") ++ else() ++ set(LLVM_PARALLEL_COMPILE_JOBS "${number_of_logical_cores}") ++ endif() ++endif() + if(LLVM_PARALLEL_COMPILE_JOBS) + if(NOT CMAKE_GENERATOR MATCHES "Ninja") + message(WARNING "Job pooling is only available with Ninja generators.") +@@ -44,6 +59,17 @@ endif() + + set(LLVM_PARALLEL_LINK_JOBS "" CACHE STRING + "Define the maximum number of concurrent link jobs (Ninja only).") ++if(LLVM_RAM_PER_LINK_JOB) ++math(EXPR jobs_with_sufficient_memory "${available_physical_memory} / ${LLVM_RAM_PER_LINK_JOB}" OUTPUT_FORMAT DECIMAL) ++if (jobs_with_sufficient_memory LESS 1) ++ set(jobs_with_sufficient_memory 1) ++endif() ++if (jobs_with_sufficient_memory LESS number_of_logical_cores) ++ set(LLVM_PARALLEL_LINK_JOBS "${jobs_with_sufficient_memory}") ++else() ++ set(LLVM_PARALLEL_LINK_JOBS "${number_of_logical_cores}") ++endif() ++endif() + if(CMAKE_GENERATOR MATCHES "Ninja") + if(NOT LLVM_PARALLEL_LINK_JOBS AND uppercase_LLVM_ENABLE_LTO STREQUAL "THIN") + message(STATUS "ThinLTO provides its own parallel linking - limiting parallel link jobs to 2.") diff --git a/utils/conan/llvm-core/all/patches/14x/0002-missing-includes.patch b/utils/conan/llvm-core/all/patches/14x/0002-missing-includes.patch new file mode 100644 index 000000000..c7cfb9031 --- /dev/null +++ b/utils/conan/llvm-core/all/patches/14x/0002-missing-includes.patch @@ -0,0 +1,12 @@ +diff --git a/include/llvm/Support/Signals.h b/include/llvm/Support/Signals.h +index 44f5a750ff5..937e0572d4a 100644 +--- a/include/llvm/Support/Signals.h ++++ b/include/llvm/Support/Signals.h +@@ -14,6 +14,7 @@ + #ifndef LLVM_SUPPORT_SIGNALS_H + #define LLVM_SUPPORT_SIGNALS_H + ++#include + #include + + namespace llvm { diff --git a/utils/conan/llvm-core/all/patches/14x/0003-no-build-with-install-rpath.patch b/utils/conan/llvm-core/all/patches/14x/0003-no-build-with-install-rpath.patch new file mode 100644 index 000000000..143952603 --- /dev/null +++ b/utils/conan/llvm-core/all/patches/14x/0003-no-build-with-install-rpath.patch @@ -0,0 +1,13 @@ +diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake +index 37bc98f9e021..2220fef943d2 100644 +--- a/cmake/modules/AddLLVM.cmake ++++ b/cmake/modules/AddLLVM.cmake +@@ -2168,7 +2168,7 @@ function(llvm_setup_rpath name) + + # Enable BUILD_WITH_INSTALL_RPATH unless CMAKE_BUILD_RPATH is set. + if("${CMAKE_BUILD_RPATH}" STREQUAL "") +- set_property(TARGET ${name} PROPERTY BUILD_WITH_INSTALL_RPATH ON) ++ set_property(TARGET ${name} PROPERTY BUILD_WITH_INSTALL_RPATH OFF) + endif() + + set_target_properties(${name} PROPERTIES diff --git a/utils/conan/llvm-core/all/patches/14x/0004-remove-lto-exports.patch b/utils/conan/llvm-core/all/patches/14x/0004-remove-lto-exports.patch new file mode 100644 index 000000000..944d4d2f3 --- /dev/null +++ b/utils/conan/llvm-core/all/patches/14x/0004-remove-lto-exports.patch @@ -0,0 +1,32 @@ +diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports +index 3abae5f0fcba..4164c3919a97 100644 +--- a/tools/lto/lto.exports ++++ b/tools/lto/lto.exports +@@ -45,12 +45,6 @@ lto_codegen_compile_optimized + lto_codegen_set_should_internalize + lto_codegen_set_should_embed_uselists + lto_set_debug_options +-LLVMCreateDisasm +-LLVMCreateDisasmCPU +-LLVMDisasmDispose +-LLVMDisasmInstruction +-LLVMSetDisasmOptions +-LLVMCreateDisasmCPUFeatures + thinlto_create_codegen + thinlto_codegen_dispose + thinlto_codegen_add_module +diff --git a/tools/remarks-shlib/CMakeLists.txt b/tools/remarks-shlib/CMakeLists.txt +index f22cedd9ead7..bc4bd67e2c9e 100644 +--- a/tools/remarks-shlib/CMakeLists.txt ++++ b/tools/remarks-shlib/CMakeLists.txt +@@ -9,7 +9,9 @@ if(LLVM_ENABLE_PIC) + libremarks.cpp + ) + +- set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Remarks.exports) ++ if (NOT (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB)) ++ set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Remarks.exports) ++ endif() + + add_llvm_library(Remarks SHARED INSTALL_WITH_TOOLCHAIN ${SOURCES}) + diff --git a/utils/conan/llvm-core/all/test_package/CMakeLists.txt b/utils/conan/llvm-core/all/test_package/CMakeLists.txt new file mode 100644 index 000000000..4de381029 --- /dev/null +++ b/utils/conan/llvm-core/all/test_package/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.15) +project(test_package LANGUAGES CXX) + +macro(test_llvm_cmake_variable VARIABLE) + if(NOT DEFINED ${VARIABLE}) + message(FATAL_ERROR "${VARIABLE} is not defined") + endif() + message(STATUS "${VARIABLE}: ${${VARIABLE}}") +endmacro() + +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME} test_package.cpp) + +if (LLVM_SHARED) + find_package(LLVM REQUIRED) + target_link_libraries(${PROJECT_NAME} PRIVATE LLVM) +else() + find_package(LLVM REQUIRED) + llvm_map_components_to_libnames(llvm_libs interpreter nativecodegen irreader) + target_link_libraries(${PROJECT_NAME} PRIVATE ${llvm_libs}) +endif() + +message(STATUS "Testing LLVM Build Module Variables") +test_llvm_cmake_variable(LLVM_PACKAGE_VERSION) +test_llvm_cmake_variable(LLVM_BUILD_TYPE) +test_llvm_cmake_variable(LLVM_CMAKE_DIR) +test_llvm_cmake_variable(LLVM_TOOLS_BINARY_DIR) +test_llvm_cmake_variable(LLVM_ALL_TARGETS) +test_llvm_cmake_variable(LLVM_TARGETS_TO_BUILD) +test_llvm_cmake_variable(LLVM_TARGETS_WITH_JIT) +test_llvm_cmake_variable(LLVM_NATIVE_ARCH) diff --git a/utils/conan/llvm-core/all/test_package/conanfile.py b/utils/conan/llvm-core/all/test_package/conanfile.py new file mode 100644 index 000000000..5ae2ff91c --- /dev/null +++ b/utils/conan/llvm-core/all/test_package/conanfile.py @@ -0,0 +1,43 @@ +from conan import ConanFile +from conan.tools.cmake import cmake_layout, CMakeDeps, CMakeToolchain, CMake +from conan.tools.env import VirtualRunEnv +from conan.tools.build import can_run + +import os + + +class TestPackageConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + + def layout(self): + cmake_layout(self) + + def requirements(self): + self.requires(self.tested_reference_str) + + def build_requirements(self): + # required for cmake_path support + self.tool_requires("cmake/[>=3.20 <4]") + + def generate(self): + deps = CMakeDeps(self) + deps.check_components_exist = True + deps.generate() + + tc = CMakeToolchain(self) + if self.dependencies[self.tested_reference_str].options.shared: + tc.variables["LLVM_SHARED"] = True + tc.generate() + + VirtualRunEnv(self).generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if can_run(self): + cmd = os.path.join(self.cpp.build.bindir, "test_package") + args = os.path.join(os.path.dirname(__file__), "test_function.ll") + self.run(f"{cmd} {args}", env="conanrun") diff --git a/utils/conan/llvm-core/all/test_package/test_function.ll b/utils/conan/llvm-core/all/test_package/test_function.ll new file mode 100644 index 000000000..6e62088cd --- /dev/null +++ b/utils/conan/llvm-core/all/test_package/test_function.ll @@ -0,0 +1,6 @@ +@.str = private unnamed_addr constant [25 x i8] c"LLVM IR interpreter ok!\0A\00", align 1 +define i32 @test() #0 { + call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str, i64 0, i64 0)) + ret i32 0 +} +declare i32 @printf(i8*, ...) #1 diff --git a/utils/conan/llvm-core/all/test_package/test_package.cpp b/utils/conan/llvm-core/all/test_package/test_package.cpp new file mode 100644 index 000000000..e5de3a64a --- /dev/null +++ b/utils/conan/llvm-core/all/test_package/test_package.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + + +int main(int argc, char const* argv[]) { + if (argc < 2) + return 0; + + llvm::InitializeNativeTarget(); + llvm::SMDiagnostic smd; + llvm::LLVMContext context; + std::string error; + + llvm::EngineBuilder engine_builder{ + llvm::parseIRFile(argv[1], smd, context) + }; + engine_builder.setEngineKind(llvm::EngineKind::Interpreter); + engine_builder.setErrorStr(&error); + + auto execution_engine = std::unique_ptr( + engine_builder.create() + ); + execution_engine->runStaticConstructorsDestructors(false); + + auto test_function = execution_engine->FindFunctionNamed("test"); + auto result = execution_engine->runFunction( + test_function, + llvm::ArrayRef() + ); + return result.IntVal.getSExtValue(); +} From 0c6c9d1a5c0a7f794ed2716cbb7e780088cd11bf Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Wed, 29 Jan 2025 17:42:24 +0100 Subject: [PATCH 02/18] deploy(conan): fix nlohmann dep --- CMakeLists.txt | 25 +++++---- cmake/add_nlohmann_json.cmake | 100 ++++++++++++++++++---------------- conanfile.py | 17 +----- test_package/CMakeLists.txt | 3 +- test_package/conanfile.py | 1 - 5 files changed, 71 insertions(+), 75 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 593c04291..41f7ee06b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -431,18 +431,19 @@ if(NOT PHASAR_IN_TREE) install(TARGETS phasar_interface EXPORT PhasarExports ) - - # Install the export-set containing all the phasar targets - install(EXPORT PhasarExports - FILE PhasarExports.cmake - NAMESPACE phasar:: - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/phasar" - ) - install(EXPORT ${PHASAR_DEPS_EXPORT_SET} - FILE ${PHASAR_DEPS_EXPORT_SET}.cmake - NAMESPACE phasar:: - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/phasar" - ) + if (NOT PHASAR_USE_CONAN) + # Install the export-set containing all the phasar targets + install(EXPORT PhasarExports + FILE PhasarExports.cmake + NAMESPACE phasar:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/phasar" + ) + install(EXPORT ${PHASAR_DEPS_EXPORT_SET} + FILE ${PHASAR_DEPS_EXPORT_SET}.cmake + NAMESPACE phasar:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/phasar" + ) + endif() else() install(TARGETS phasar_interface EXPORT LLVMExports diff --git a/cmake/add_nlohmann_json.cmake b/cmake/add_nlohmann_json.cmake index 0d929706c..8cfd3f69c 100644 --- a/cmake/add_nlohmann_json.cmake +++ b/cmake/add_nlohmann_json.cmake @@ -1,60 +1,68 @@ function(add_nlohmann_json) - set(JSON_BuildTests OFF) - set(JSON_Install OFF) + if (PHASAR_USE_CONAN) + find_package(nlohmann_json REQUIRED) + else() + set(JSON_BuildTests OFF) + set(JSON_Install OFF) - if (PHASAR_IN_TREE) - set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json) - endif() + if (PHASAR_IN_TREE) + set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json) + endif() + + add_subdirectory(external/json EXCLUDE_FROM_ALL) + set_property(TARGET nlohmann_json APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES $ + ) - add_subdirectory(external/json EXCLUDE_FROM_ALL) - set_property(TARGET nlohmann_json APPEND PROPERTY - INTERFACE_INCLUDE_DIRECTORIES $ - ) - - install(TARGETS nlohmann_json - EXPORT ${PHASAR_DEPS_EXPORT_SET} - LIBRARY DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib - ARCHIVE DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib - RUNTIME DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/bin - ) - install(DIRECTORY external/json/include/ - DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/include - ) + install(TARGETS nlohmann_json + EXPORT ${PHASAR_DEPS_EXPORT_SET} + LIBRARY DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib + ARCHIVE DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib + RUNTIME DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/bin + ) + install(DIRECTORY external/json/include/ + DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/include + ) + endif() endfunction() function(add_json_schema_validator) - # We need to work around the behavior of nlohmann_json_schema_validator and nlohmann_json here - # The validator needs the json part, but if you include it, the library of nlohmann_json_schema_validator - # is not installed, leading to linker error. But just including nlohmann_json is not sufficient, as - # in the installed state the nlohmann_json_schema_validator needs the nlohmann_json package which needs - # to be installed. - # The following workaround may collapse or become unnecessary once the issue is - # changed or fixed in nlohmann_json_schema_validator. - if (PHASAR_IN_TREE) - set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json_schema_validator) - endif() + if (PHASAR_USE_CONAN) + find_package(nlohmann_json_schema_validator REQUIRED) + else() + # We need to work around the behavior of nlohmann_json_schema_validator and nlohmann_json here + # The validator needs the json part, but if you include it, the library of nlohmann_json_schema_validator + # is not installed, leading to linker error. But just including nlohmann_json is not sufficient, as + # in the installed state the nlohmann_json_schema_validator needs the nlohmann_json package which needs + # to be installed. + # The following workaround may collapse or become unnecessary once the issue is + # changed or fixed in nlohmann_json_schema_validator. + if (PHASAR_IN_TREE) + set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS nlohmann_json_schema_validator) + endif() - set(JSON_VALIDATOR_INSTALL OFF) + set(JSON_VALIDATOR_INSTALL OFF) - set(BUILD_SHARED_LIBS_SAVE ${BUILD_SHARED_LIBS}) - set(BUILD_SHARED_LIBS OFF) + set(BUILD_SHARED_LIBS_SAVE ${BUILD_SHARED_LIBS}) + set(BUILD_SHARED_LIBS OFF) - add_subdirectory(external/json-schema-validator EXCLUDE_FROM_ALL) + add_subdirectory(external/json-schema-validator EXCLUDE_FROM_ALL) - set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_SAVE}) + set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_SAVE}) - set_property(TARGET nlohmann_json_schema_validator APPEND PROPERTY - INTERFACE_INCLUDE_DIRECTORIES $ - ) + set_property(TARGET nlohmann_json_schema_validator APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES $ + ) - install(TARGETS nlohmann_json_schema_validator - EXPORT ${PHASAR_DEPS_EXPORT_SET} - LIBRARY DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib - ARCHIVE DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib - RUNTIME DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/bin - ) - install(FILES external/json-schema-validator/src/nlohmann/json-schema.hpp - DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/include/nlohmann - ) + install(TARGETS nlohmann_json_schema_validator + EXPORT ${PHASAR_DEPS_EXPORT_SET} + LIBRARY DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib + ARCHIVE DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/lib + RUNTIME DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/bin + ) + install(FILES external/json-schema-validator/src/nlohmann/json-schema.hpp + DESTINATION ${PHASAR_DEPS_INSTALL_DESTINATION}/include/nlohmann + ) + endif() endfunction() diff --git a/conanfile.py b/conanfile.py index ced7a9bed..95cde6661 100644 --- a/conanfile.py +++ b/conanfile.py @@ -2,17 +2,10 @@ from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps from conan.tools.build import check_min_cppstd from conan.tools.files import ( - apply_conandata_patches, - collect_libs, - get, - rmdir, load, save, copy, - export_conandata_patches, rm, - rename, - replace_in_file ) from conan.tools.scm import Git from os.path import join @@ -29,6 +22,7 @@ def node_labels(dot): "zstd::libzstd_static": "zstd::zstdlib", "-lpthread": "pthread", "curl": "libcurl::libcurl", + "nlohmann_json_schema_validator": "json-schema-validator::json-schema-validator" } for row in dot: # e.g. "node0" [ label = "phasar\n(phasar::phasar)", shape = octagon ]; @@ -47,10 +41,8 @@ def node_labels(dot): def node_dependencies(dot): ignore_deps = [ - "nlohmann_json_schema_validator" ] labels = {k: v for k, v in node_labels(dot)} - # raise Exception(labels) for row in dot: # "node0" -> "node1" [ style = dashed ] // phasar -> LLVMAnalysis match_dep = re.match(r'''^\s*"(node[0-9]+)"\s*->\s*"(node[0-9]+)".*''', row) @@ -154,8 +146,8 @@ def requirements(self): self.requires("sqlite3/[>=3 <4]") self.requires("libcurl/[>=7 <9]") self.requires("clang/14.0.6", transitive_libs=True, transitive_headers=True) - self.requires("nlohmann_json/3.11.3", build=True, headers=True, libs=False, transitive_headers=True) - self.requires("json-schema-validator/2.3.0", build=True, headers=True, libs=False, transitive_headers=True) + self.requires("nlohmann_json/3.11.3", transitive_headers=True) + self.requires("json-schema-validator/2.3.0", transitive_libs=True, transitive_headers=True) llvm_options={ "rtti": True, @@ -287,9 +279,6 @@ def package_info(self): components = build_info["components"] for component_name, data in components.items(): - req = data["requires"] - sys = data["system_libs"] - self.output.info(f"{component_name}: \nrequires:{req}\nsystem:{sys}") self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) self.cpp_info.components[component_name].libs = [component_name] self.cpp_info.components[component_name].requires = data["requires"] diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index a25a2c601..73957a455 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.1) project(phasar-PackageTest CXX C) find_package(phasar CONFIG REQUIRED) -find_package(nlohmann_json REQUIRED) add_executable(myphasartool myphasartool.cpp) set_property(TARGET myphasartool PROPERTY CXX_STANDARD 17) @@ -10,4 +9,4 @@ set_property(TARGET myphasartool PROPERTY EXPORT_COMPILE_COMMANDS YES) set_property(TARGET myphasartool PROPERTY CXX_STANDARD_REQUIRED ON) set_property(TARGET myphasartool PROPERTY CXX_EXTENSIONS OFF) -target_link_libraries(myphasartool PUBLIC phasar::phasar nlohmann_json::nlohmann_json) +target_link_libraries(myphasartool PUBLIC phasar::phasar) diff --git a/test_package/conanfile.py b/test_package/conanfile.py index b30306362..ecc090713 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -10,7 +10,6 @@ class PhasarTestConan(ConanFile): def requirements(self): self.requires(self.tested_reference_str) - self.requires("nlohmann_json/3.11.3") def build(self): cmake = CMake(self) From eacf8b855b121c5e89d636746890876166ce471f Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Wed, 29 Jan 2025 17:43:33 +0100 Subject: [PATCH 03/18] deploy(conan): fix clang should be linked static --- conanfile.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conanfile.py b/conanfile.py index 95cde6661..deec13774 100644 --- a/conanfile.py +++ b/conanfile.py @@ -32,10 +32,15 @@ def node_labels(dot): label = match_label.group(2) if label.startswith("LLVM"): yield node, f"llvm-core::{label}" + # XXX find_library adds direct filepath -> imho a flaw in current cmake files elif label.endswith("libsqlite3.a"): yield node, "sqlite3::sqlite3" elif label.endswith("libclang-cpp.so"): yield node, "clang::clang" + elif label.endswith("libclangCodeGen.a"): + yield node, "clang::clangCodeGen" + elif label.endswith("libclangTooling.a"): + yield node, "clang::clangTooling" else: yield node, label_replacements.get(label, label) From b31e4ce371b6b1df6c2d0b35f18cb6ae14e6994c Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Thu, 30 Jan 2025 14:38:32 +0100 Subject: [PATCH 04/18] deploy(conan): recipe requires v2 --- conanfile.py | 4 +++- test_package/conanfile.py | 2 +- test_package/test.sh | 8 -------- 3 files changed, 4 insertions(+), 10 deletions(-) delete mode 100755 test_package/test.sh diff --git a/conanfile.py b/conanfile.py index deec13774..51fd09289 100644 --- a/conanfile.py +++ b/conanfile.py @@ -14,6 +14,8 @@ import textwrap import json +required_conan_version = ">=2.0" + def components_from_dotfile(dotfile): def node_labels(dot): label_replacements = { @@ -147,7 +149,7 @@ def config_options(self): self.options.rm_safe("fPIC") def requirements(self): - self.requires("boost/[>1.72.0 <=1.81.0]") + self.requires("boost/[>1.72.0 1.86.0<=]") self.requires("sqlite3/[>=3 <4]") self.requires("libcurl/[>=7 <9]") self.requires("clang/14.0.6", transitive_libs=True, transitive_headers=True) diff --git a/test_package/conanfile.py b/test_package/conanfile.py index ecc090713..79a69857d 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -22,4 +22,4 @@ def layout(self): def test(self): if can_run(self): example = os.path.join(os.path.dirname(__file__), 'example.ll') - self.run(f"./myphasartool \"{example}\"", cwd=self.cpp.build.bindir, env="conanrun") #env="conanrun" run_environment=True + self.run(f"./myphasartool \"{example}\"", cwd=self.cpp.build.bindir, env="conanrun") diff --git a/test_package/test.sh b/test_package/test.sh deleted file mode 100755 index 917d0f714..000000000 --- a/test_package/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -( - cd "$(dirname "$0")/.." - conan create -o "phasar/*:unittests=False" . -) From af483c882f47585d7afb0192ab9fe10c0cf081cb Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 3 Feb 2025 12:05:57 +0100 Subject: [PATCH 05/18] deploy(conan): fix deps recipes --- .../14x/0000-force-import-original-llvm-config.patch | 0 utils/conan/llvm-core/all/test_package/test_function.ll | 6 ------ utils/conan/llvm-core/{all => }/conandata.yml | 0 utils/conan/llvm-core/{all => }/conanfile.py | 0 .../{all => }/patches/14x/0000-cmake-dependencies.patch | 0 .../{all => }/patches/14x/0001-calculate-job-pools.patch | 0 .../{all => }/patches/14x/0002-missing-includes.patch | 0 .../patches/14x/0003-no-build-with-install-rpath.patch | 0 .../{all => }/patches/14x/0004-remove-lto-exports.patch | 0 utils/conan/llvm-core/{all => }/test_package/CMakeLists.txt | 0 utils/conan/llvm-core/{all => }/test_package/conanfile.py | 0 .../conan/llvm-core/{all => }/test_package/test_package.cpp | 0 12 files changed, 6 deletions(-) rename utils/conan/clang/{ => patches}/14x/0000-force-import-original-llvm-config.patch (100%) delete mode 100644 utils/conan/llvm-core/all/test_package/test_function.ll rename utils/conan/llvm-core/{all => }/conandata.yml (100%) rename utils/conan/llvm-core/{all => }/conanfile.py (100%) rename utils/conan/llvm-core/{all => }/patches/14x/0000-cmake-dependencies.patch (100%) rename utils/conan/llvm-core/{all => }/patches/14x/0001-calculate-job-pools.patch (100%) rename utils/conan/llvm-core/{all => }/patches/14x/0002-missing-includes.patch (100%) rename utils/conan/llvm-core/{all => }/patches/14x/0003-no-build-with-install-rpath.patch (100%) rename utils/conan/llvm-core/{all => }/patches/14x/0004-remove-lto-exports.patch (100%) rename utils/conan/llvm-core/{all => }/test_package/CMakeLists.txt (100%) rename utils/conan/llvm-core/{all => }/test_package/conanfile.py (100%) rename utils/conan/llvm-core/{all => }/test_package/test_package.cpp (100%) diff --git a/utils/conan/clang/14x/0000-force-import-original-llvm-config.patch b/utils/conan/clang/patches/14x/0000-force-import-original-llvm-config.patch similarity index 100% rename from utils/conan/clang/14x/0000-force-import-original-llvm-config.patch rename to utils/conan/clang/patches/14x/0000-force-import-original-llvm-config.patch diff --git a/utils/conan/llvm-core/all/test_package/test_function.ll b/utils/conan/llvm-core/all/test_package/test_function.ll deleted file mode 100644 index 6e62088cd..000000000 --- a/utils/conan/llvm-core/all/test_package/test_function.ll +++ /dev/null @@ -1,6 +0,0 @@ -@.str = private unnamed_addr constant [25 x i8] c"LLVM IR interpreter ok!\0A\00", align 1 -define i32 @test() #0 { - call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str, i64 0, i64 0)) - ret i32 0 -} -declare i32 @printf(i8*, ...) #1 diff --git a/utils/conan/llvm-core/all/conandata.yml b/utils/conan/llvm-core/conandata.yml similarity index 100% rename from utils/conan/llvm-core/all/conandata.yml rename to utils/conan/llvm-core/conandata.yml diff --git a/utils/conan/llvm-core/all/conanfile.py b/utils/conan/llvm-core/conanfile.py similarity index 100% rename from utils/conan/llvm-core/all/conanfile.py rename to utils/conan/llvm-core/conanfile.py diff --git a/utils/conan/llvm-core/all/patches/14x/0000-cmake-dependencies.patch b/utils/conan/llvm-core/patches/14x/0000-cmake-dependencies.patch similarity index 100% rename from utils/conan/llvm-core/all/patches/14x/0000-cmake-dependencies.patch rename to utils/conan/llvm-core/patches/14x/0000-cmake-dependencies.patch diff --git a/utils/conan/llvm-core/all/patches/14x/0001-calculate-job-pools.patch b/utils/conan/llvm-core/patches/14x/0001-calculate-job-pools.patch similarity index 100% rename from utils/conan/llvm-core/all/patches/14x/0001-calculate-job-pools.patch rename to utils/conan/llvm-core/patches/14x/0001-calculate-job-pools.patch diff --git a/utils/conan/llvm-core/all/patches/14x/0002-missing-includes.patch b/utils/conan/llvm-core/patches/14x/0002-missing-includes.patch similarity index 100% rename from utils/conan/llvm-core/all/patches/14x/0002-missing-includes.patch rename to utils/conan/llvm-core/patches/14x/0002-missing-includes.patch diff --git a/utils/conan/llvm-core/all/patches/14x/0003-no-build-with-install-rpath.patch b/utils/conan/llvm-core/patches/14x/0003-no-build-with-install-rpath.patch similarity index 100% rename from utils/conan/llvm-core/all/patches/14x/0003-no-build-with-install-rpath.patch rename to utils/conan/llvm-core/patches/14x/0003-no-build-with-install-rpath.patch diff --git a/utils/conan/llvm-core/all/patches/14x/0004-remove-lto-exports.patch b/utils/conan/llvm-core/patches/14x/0004-remove-lto-exports.patch similarity index 100% rename from utils/conan/llvm-core/all/patches/14x/0004-remove-lto-exports.patch rename to utils/conan/llvm-core/patches/14x/0004-remove-lto-exports.patch diff --git a/utils/conan/llvm-core/all/test_package/CMakeLists.txt b/utils/conan/llvm-core/test_package/CMakeLists.txt similarity index 100% rename from utils/conan/llvm-core/all/test_package/CMakeLists.txt rename to utils/conan/llvm-core/test_package/CMakeLists.txt diff --git a/utils/conan/llvm-core/all/test_package/conanfile.py b/utils/conan/llvm-core/test_package/conanfile.py similarity index 100% rename from utils/conan/llvm-core/all/test_package/conanfile.py rename to utils/conan/llvm-core/test_package/conanfile.py diff --git a/utils/conan/llvm-core/all/test_package/test_package.cpp b/utils/conan/llvm-core/test_package/test_package.cpp similarity index 100% rename from utils/conan/llvm-core/all/test_package/test_package.cpp rename to utils/conan/llvm-core/test_package/test_package.cpp From aa42a7e9ce40e4cda0b5002cdbe82a1cb2ffbdfa Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 3 Feb 2025 14:21:07 +0100 Subject: [PATCH 06/18] deploy(conan): recipes should use proper user --- README.md | 10 ++- conanfile.py | 103 ++++++++++++++++++++++++----- utils/conan/clang/conanfile.py | 25 +++++-- utils/conan/llvm-core/conanfile.py | 19 ++++++ 4 files changed, 134 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index d7ceb3cd9..8328973f2 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ sudo ninja install ## How to use PhASAR? -We recomment using phasar as a library with `cmake`. +We recomment using phasar as a library with `cmake` or `conan`. If you already have installed phasar, [Use-PhASAR-as-a-library](https://github.com/secure-software-engineering/phasar/wiki/Using-Phasar-as-a-Library) may be a good start. @@ -200,6 +200,14 @@ Depending on your use of PhASAR you also may need to add LLVM to your build. For more information please consult our [PhASAR wiki pages](https://github.com/secure-software-engineering/phasar/wiki). +## How to use with Conan v2 ? + +To export the recipe and dependencies execute from repo root: +- `conan export utils/conan/llvm-core/ --version 14.0.6` +- `conan export utils/conan/clang/ --version 14.0.6` +- `conan export .` +- View exported`conan list "phasar/*"` +- [Consume the package](https://docs.conan.io/2/tutorial/consuming_packages.html) ## Please help us to improve PhASAR diff --git a/conanfile.py b/conanfile.py index 51fd09289..a9f2460ab 100644 --- a/conanfile.py +++ b/conanfile.py @@ -8,23 +8,29 @@ rm, ) from conan.tools.scm import Git -from os.path import join +from os.path import join, isdir import re from pathlib import Path, PurePosixPath import textwrap import json +import os +from conan.errors import ConanException required_conan_version = ">=2.0" def components_from_dotfile(dotfile): def node_labels(dot): + # here we are mapping dependencies visible to cmake to component dependencies in conan label_replacements = { "LibXml2::LibXml2": "libxml2::libxml2", "ZLIB::ZLIB": "zlib::zlib", "zstd::libzstd_static": "zstd::zstdlib", "-lpthread": "pthread", "curl": "libcurl::libcurl", - "nlohmann_json_schema_validator": "json-schema-validator::json-schema-validator" + "nlohmann_json_schema_validator": "json-schema-validator::json-schema-validator", + "clangCodeGen": "clang::clangCodeGen", + "clangTooling": "clang::clangTooling", + "SQLite::SQLite3": "sqlite3::sqlite3", } for row in dot: # e.g. "node0" [ label = "phasar\n(phasar::phasar)", shape = octagon ]; @@ -111,7 +117,6 @@ class PhasarRecipe(ConanFile): "shared": [True, False], "fPIC": [True, False], "tests": [True, False], - "run_tests": [True, False], "use_project_cmake_config": [True, False], } default_options = { @@ -119,28 +124,89 @@ class PhasarRecipe(ConanFile): "shared": False, "fPIC": True, "tests": False, - "run_tests": False, "use_project_cmake_config": False } + exports = [ + "conanfile.py", + "test_package/**", + "!test_package/build/**" + ] + + def _parse_gitignore(self, folder, additional_exclusions = [], invert=False): + exclusions = [] + inclusions = [] + if invert: + for exc in additional_exclusions: + if exc.startswith("!"): + inclusions = exc[1:] + else: + inclusions = f"!{exc}" + else: + exclusions = additional_exclusions + + with open(f'{folder}/.gitignore', 'r') as file: + for line in file: + line = line.strip() + if line.startswith("#") or not line: + continue + if invert: + if line.startswith("!"): + inclusions.append(line[1:]) + else: + inclusions.append("!" + line) + else: + exclusions.append(line) + + if invert: + return inclusions + else: + return exclusions + + def export_sources(self): + exclusions = self._parse_gitignore(".", [ + "test_package", + "utils", + "img", + "githooks", + "external" + ]) + + for tlf in os.listdir("."): + if isdir(tlf): + copy(self, f"{tlf}/*", src=".", dst=self.export_sources_folder, excludes=exclusions) + else: + copy(self, tlf, src=".", dst=self.export_sources_folder, excludes=exclusions) + @property def _graphviz_file(self): return PurePosixPath(self.build_folder) / "graph" / "phasar.dot" + @property + def user(self): + # user attribute should be owning git "user/org" + # e.g. "https://github.com/secure-software-engineering/phasar.git", + # "git@github.com:secure-software-engineering/phasar.git" + # => secure-software-engineering + git = Git(self, self.recipe_folder) + remote_url = git.get_remote_url(remote='origin') + match = re.search("[:/]([^/]+)/[^/]+\.git", remote_url) + if match: + return match.group(1) + else: + return None + def set_version(self): git = Git(self, self.recipe_folder) - # git.coordinates_to_conandata() + # XXX consider git.coordinates_to_conandata() if self.version is None: + if git.is_dirty(): + raise ConanException("Repository is dirty. I can't calculate a correct version and this is a potential leak because all files visible to git will be exported. Please stash or commit.") self.output.info("No version information set, retrieving from git.") calver = git.run("show -s --date=format:'%Y.%m.%d' --format='%cd'") short_hash = git.run("show -s --format='%h'") self.version = f"{calver}+{short_hash}" - def export_sources(self): - copy(self, "cmake/*", self.recipe_folder, self.export_sources_folder) - copy(self, "phasar/*", self.recipe_folder, self.export_sources_folder) - copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder) - def layout(self): cmake_layout(self) @@ -149,25 +215,25 @@ def config_options(self): self.options.rm_safe("fPIC") def requirements(self): - self.requires("boost/[>1.72.0 1.86.0<=]") + self.requires("boost/[>1.72.0 <=1.86.0]") self.requires("sqlite3/[>=3 <4]") - self.requires("libcurl/[>=7 <9]") - self.requires("clang/14.0.6", transitive_libs=True, transitive_headers=True) + self.requires("clang/14.0.6@secure-software-engineering", transitive_libs=True, transitive_headers=True) self.requires("nlohmann_json/3.11.3", transitive_headers=True) self.requires("json-schema-validator/2.3.0", transitive_libs=True, transitive_headers=True) - + llvm_options={ "rtti": True, } if self.options.with_z3: self.requires("z3/[>=4.7.1 <5]") llvm_options["with_z3"] = True - self.requires("llvm-core/14.0.6", transitive_libs=True, transitive_headers=True, options=llvm_options) + self.requires("llvm-core/14.0.6@secure-software-engineering", transitive_libs=True, transitive_headers=True, options=llvm_options) def build_requirements(self): self.tool_requires("cmake/[>=3.25.0 <4.0.0]") # find_program validator self.tool_requires("ninja/[>=1.9.0 <2.0.0]") if self.options.tests: + self.test_requires("openssl/[>2 <4]") self.test_requires("gtest/1.14.0") def configure(self): @@ -223,7 +289,7 @@ def _handle_graphviz(self): def build(self): cmake = self._cmake_configure() cmake.build() - if self.options.run_tests: + if self.options.tests: cmake.ctest(cli_args=[ "--exclude-regex 'IDEExtendedTaintAnalysisTest.*'", # known flaky test "--no-tests=error", @@ -260,7 +326,6 @@ def _read_build_info(self) -> dict: def package_id(self): del self.info.options.tests - del self.info.options.run_tests def package(self): copy(self, "LICENSE.txt", self.source_folder, join(self.package_folder, "licenses")) @@ -282,12 +347,14 @@ def package_info(self): else: self.cpp_info.set_property("cmake_file_name", "phasar") + interfaces = ["phasar_interface"] + build_info = self._read_build_info() components = build_info["components"] for component_name, data in components.items(): self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) - self.cpp_info.components[component_name].libs = [component_name] + self.cpp_info.components[component_name].libs = [component_name] if component_name not in interfaces else [] self.cpp_info.components[component_name].requires = data["requires"] self.cpp_info.components[component_name].system_libs = data["system_libs"] diff --git a/utils/conan/clang/conanfile.py b/utils/conan/clang/conanfile.py index c1c0132c4..f0ea796a3 100644 --- a/utils/conan/clang/conanfile.py +++ b/utils/conan/clang/conanfile.py @@ -7,23 +7,22 @@ from conan.errors import ConanInvalidConfiguration from conan.tools.build import check_min_cppstd from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout -from conan.tools.env import VirtualBuildEnv from conan.tools.files import ( apply_conandata_patches, copy, export_conandata_patches, get, collect_libs, - replace_in_file, rm, rmdir, save, load, rename ) -from conan.tools.microsoft import check_min_vs, is_msvc, is_msvc_static_runtime +from conan.tools.microsoft import is_msvc from conan.tools.scm import Version from os.path import join +from conan.tools.scm import Git required_conan_version = ">=2.0" @@ -61,6 +60,24 @@ def _compilers_minimum_version(self): "msvc": "191", "Visual Studio": "15", } + + _user = None + + @property + def user(self): + # user attribute should be owning git "user/org" + # e.g. "https://github.com/secure-software-engineering/phasar.git", + # "git@github.com:secure-software-engineering/phasar.git" + # => secure-software-engineering + if self._user is None: + git = Git(self, self.recipe_folder) + remote_url = git.get_remote_url(remote='origin') + match = re.search("[:/]([^/]+)/[^/]+\.git", remote_url) + if match: + self._user = match.group(1) + else: + self._user = None + return self._user def export_sources(self): export_conandata_patches(self) @@ -84,7 +101,7 @@ def build_requirements(self): self.test_requires("libxml2/[>=2.5.3 <3]") def requirements(self): - self.requires(f"llvm-core/{self.version}", transitive_headers=True, transitive_libs=True) + self.requires(f"llvm-core/{self.version}@secure-software-engineering", transitive_headers=True, transitive_libs=True) def validate(self): if self.settings.compiler.cppstd: diff --git a/utils/conan/llvm-core/conanfile.py b/utils/conan/llvm-core/conanfile.py index 119832b8e..8e3c5495f 100644 --- a/utils/conan/llvm-core/conanfile.py +++ b/utils/conan/llvm-core/conanfile.py @@ -24,6 +24,7 @@ from pathlib import Path import re import textwrap +from conan.tools.scm import Git required_conan_version = ">=1.62.0" @@ -131,6 +132,24 @@ def _compilers_minimum_version(self): "Visual Studio": "15", } + _user = None + + @property + def user(self): + # user attribute should be owning git "user/org" + # e.g. "https://github.com/secure-software-engineering/phasar.git", + # "git@github.com:secure-software-engineering/phasar.git" + # => secure-software-engineering + if self._user is None: + git = Git(self, self.recipe_folder) + remote_url = git.get_remote_url(remote='origin') + match = re.search("[:/]([^/]+)/[^/]+\.git", remote_url) + if match: + self._user = match.group(1) + else: + self._user = None + return self._user + def export_sources(self): export_conandata_patches(self) From 952cb5a9ade6ef426d09d0017d19e879cba00b0e Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 3 Feb 2025 16:08:31 +0100 Subject: [PATCH 07/18] deploy(conan): fix dyn user / version --- README.md | 4 +-- conanfile.py | 49 +++++++++++++++++++----------- utils/conan/clang/conanfile.py | 18 ----------- utils/conan/llvm-core/conanfile.py | 18 ----------- 4 files changed, 34 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 8328973f2..d41cb9719 100644 --- a/README.md +++ b/README.md @@ -203,8 +203,8 @@ For more information please consult our [PhASAR wiki pages](https://github.com/s ## How to use with Conan v2 ? To export the recipe and dependencies execute from repo root: -- `conan export utils/conan/llvm-core/ --version 14.0.6` -- `conan export utils/conan/clang/ --version 14.0.6` +- `conan export utils/conan/llvm-core/ --version 14.0.6 --user secure-software-engineering` +- `conan export utils/conan/clang/ --version 14.0.6 --user secure-software-engineering` - `conan export .` - View exported`conan list "phasar/*"` - [Consume the package](https://docs.conan.io/2/tutorial/consuming_packages.html) diff --git a/conanfile.py b/conanfile.py index a9f2460ab..c2000413c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -8,7 +8,7 @@ rm, ) from conan.tools.scm import Git -from os.path import join, isdir +from os.path import join, isdir, exists import re from pathlib import Path, PurePosixPath import textwrap @@ -183,29 +183,44 @@ def _graphviz_file(self): return PurePosixPath(self.build_folder) / "graph" / "phasar.dot" @property - def user(self): - # user attribute should be owning git "user/org" - # e.g. "https://github.com/secure-software-engineering/phasar.git", - # "git@github.com:secure-software-engineering/phasar.git" - # => secure-software-engineering - git = Git(self, self.recipe_folder) - remote_url = git.get_remote_url(remote='origin') - match = re.search("[:/]([^/]+)/[^/]+\.git", remote_url) - if match: - return match.group(1) - else: + def _info_file(self): + # this is called very early where folders aren't set but this is fine + if self.export_folder is None: return None - + return PurePosixPath(self.export_folder) / "info.json" + + def _read_info(self): + if self._info_file is not None and exists(self._info_file): + with open(self._info_file, encoding="utf-8") as fp: + return json.load(fp) + else: + return { + "version": None, + } + + def _write_info(self, info): + if self._info_file is not None: + with open(self._info_file, "w", encoding="utf-8") as fp: + json.dump(info, fp, indent=2) + def set_version(self): - git = Git(self, self.recipe_folder) - # XXX consider git.coordinates_to_conandata() - if self.version is None: + if self.version is not None: + return + info = self._read_info() + version = info["version"] + if version is None: + git = Git(self, self.recipe_folder) + # XXX consider git.coordinates_to_conandata() if git.is_dirty(): raise ConanException("Repository is dirty. I can't calculate a correct version and this is a potential leak because all files visible to git will be exported. Please stash or commit.") self.output.info("No version information set, retrieving from git.") calver = git.run("show -s --date=format:'%Y.%m.%d' --format='%cd'") short_hash = git.run("show -s --format='%h'") - self.version = f"{calver}+{short_hash}" + version = f"{calver}+{short_hash}" + if info["version"] != version: + info["version"] = version + self._write_info(info) + self.version = version def layout(self): cmake_layout(self) diff --git a/utils/conan/clang/conanfile.py b/utils/conan/clang/conanfile.py index f0ea796a3..49df249de 100644 --- a/utils/conan/clang/conanfile.py +++ b/utils/conan/clang/conanfile.py @@ -61,24 +61,6 @@ def _compilers_minimum_version(self): "Visual Studio": "15", } - _user = None - - @property - def user(self): - # user attribute should be owning git "user/org" - # e.g. "https://github.com/secure-software-engineering/phasar.git", - # "git@github.com:secure-software-engineering/phasar.git" - # => secure-software-engineering - if self._user is None: - git = Git(self, self.recipe_folder) - remote_url = git.get_remote_url(remote='origin') - match = re.search("[:/]([^/]+)/[^/]+\.git", remote_url) - if match: - self._user = match.group(1) - else: - self._user = None - return self._user - def export_sources(self): export_conandata_patches(self) diff --git a/utils/conan/llvm-core/conanfile.py b/utils/conan/llvm-core/conanfile.py index 8e3c5495f..6bfc76aaf 100644 --- a/utils/conan/llvm-core/conanfile.py +++ b/utils/conan/llvm-core/conanfile.py @@ -131,24 +131,6 @@ def _compilers_minimum_version(self): "msvc": "191", "Visual Studio": "15", } - - _user = None - - @property - def user(self): - # user attribute should be owning git "user/org" - # e.g. "https://github.com/secure-software-engineering/phasar.git", - # "git@github.com:secure-software-engineering/phasar.git" - # => secure-software-engineering - if self._user is None: - git = Git(self, self.recipe_folder) - remote_url = git.get_remote_url(remote='origin') - match = re.search("[:/]([^/]+)/[^/]+\.git", remote_url) - if match: - self._user = match.group(1) - else: - self._user = None - return self._user def export_sources(self): export_conandata_patches(self) From 5d569a68a83acf1f1bc7c6471af5d63789329d30 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 3 Feb 2025 17:49:18 +0100 Subject: [PATCH 08/18] deploy(conan): default category for unknown components / linker flags --- conanfile.py | 15 +++++++-------- utils/conan/test_conan_build.sh | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) create mode 100755 utils/conan/test_conan_build.sh diff --git a/conanfile.py b/conanfile.py index c2000413c..38ff52a90 100644 --- a/conanfile.py +++ b/conanfile.py @@ -89,9 +89,14 @@ def node_dependencies(dot): components = {} dotfile_rows = dotfile.split("\n") for node, dependency in node_dependencies(dotfile_rows): - key = "system_libs" if dependency in system_libs else "requires" + if dependency in system_libs: + key = "system_libs" + elif dependency is not None and (dependency.startswith("phasar") or "::" in dependency): + key = "requires" + else: + key = "unknown" if node not in components: - components[node] = { "system_libs": [], "requires": [] } + components[node] = { "system_libs": [], "requires": [], "unknown": [] } if dependency is not None: components[node][key] = [dependency] elif dependency is not None: @@ -127,12 +132,6 @@ class PhasarRecipe(ConanFile): "use_project_cmake_config": False } - exports = [ - "conanfile.py", - "test_package/**", - "!test_package/build/**" - ] - def _parse_gitignore(self, folder, additional_exclusions = [], invert=False): exclusions = [] inclusions = [] diff --git a/utils/conan/test_conan_build.sh b/utils/conan/test_conan_build.sh new file mode 100755 index 000000000..25cd1a896 --- /dev/null +++ b/utils/conan/test_conan_build.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -euo pipefail + +( + cd "$(dirname "$0")" + cd ../.. + conan create . --version dev --build=missing -s build_type=RelWithDebInfo + cd test_package/build/ + mkdir -p Debug/generators + cd Debug/generators + conan install -of . --requires phasar/dev --build=missing -s build_type=Release -g VirtualRunEnv -g CMakeDeps + conan install -of . --requires phasar/dev --build=missing -s build_type=Debug -g VirtualRunEnv -g CMakeDeps +) \ No newline at end of file From b0ddc1ed49ad38c5b3a9f17b49af980bcaf78138 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 3 Feb 2025 23:23:16 +0100 Subject: [PATCH 09/18] deploy(conan): add fPIC --- conanfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conanfile.py b/conanfile.py index 38ff52a90..cc69a28e0 100644 --- a/conanfile.py +++ b/conanfile.py @@ -268,6 +268,7 @@ def _cmake_configure(self): self._handle_graphviz() cmake.configure( variables={ + 'PHASAR_ENABLE_PIC': self.options.get_safe("fPIC", False), 'PHASAR_USE_CONAN': True, 'BUILD_SHARED_LIBS': self.options.shared, 'PHASAR_BUILD_UNITTESTS': self.options.tests, From 946cf7b1f93a1d881cbc6a58c5f28bcece783a09 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 3 Feb 2025 23:23:52 +0100 Subject: [PATCH 10/18] deploy(conan): rm legacy package option --- conanfile.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/conanfile.py b/conanfile.py index cc69a28e0..ae56628d8 100644 --- a/conanfile.py +++ b/conanfile.py @@ -122,14 +122,12 @@ class PhasarRecipe(ConanFile): "shared": [True, False], "fPIC": [True, False], "tests": [True, False], - "use_project_cmake_config": [True, False], } default_options = { "with_z3": True, "shared": False, "fPIC": True, "tests": False, - "use_project_cmake_config": False } def _parse_gitignore(self, folder, additional_exclusions = [], invert=False): @@ -354,22 +352,16 @@ def package(self): self._write_build_info() def package_info(self): - if self.options.use_project_cmake_config: - # disable CMakeDeps and use own CMakefiles: - self.cpp_info.set_property("cmake_find_mode", "none") - self.cpp_info.builddirs.append(join("lib", "cmake", "phasar")) - - else: - self.cpp_info.set_property("cmake_file_name", "phasar") + self.cpp_info.set_property("cmake_file_name", "phasar") - interfaces = ["phasar_interface"] + interfaces = ["phasar_interface"] - build_info = self._read_build_info() - components = build_info["components"] + build_info = self._read_build_info() + components = build_info["components"] - for component_name, data in components.items(): - self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) - self.cpp_info.components[component_name].libs = [component_name] if component_name not in interfaces else [] - self.cpp_info.components[component_name].requires = data["requires"] - self.cpp_info.components[component_name].system_libs = data["system_libs"] + for component_name, data in components.items(): + self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) + self.cpp_info.components[component_name].libs = [component_name] if component_name not in interfaces else [] + self.cpp_info.components[component_name].requires = data["requires"] + self.cpp_info.components[component_name].system_libs = data["system_libs"] From 000c89287536185a3aaf07b705cc779f177138e6 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Mon, 3 Feb 2025 23:52:38 +0100 Subject: [PATCH 11/18] deploy(conan): build tools --- CMakeLists.txt | 3 ++- conanfile.py | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41f7ee06b..26fa490d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,7 +213,8 @@ else() message(STATUS "Dynamic log disabled") endif() -if (NOT PHASAR_IN_TREE) +if (PHASAR_USE_CONAN) +elseif (NOT PHASAR_IN_TREE) # RPATH set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) diff --git a/conanfile.py b/conanfile.py index ae56628d8..e36825db5 100644 --- a/conanfile.py +++ b/conanfile.py @@ -275,8 +275,7 @@ def _cmake_configure(self): 'PHASAR_USE_Z3': self.options.with_z3, 'USE_LLVM_FAT_LIB': False, 'BUILD_PHASAR_CLANG': True, - # TODO - 'PHASAR_BUILD_TOOLS': False, + 'PHASAR_BUILD_TOOLS': True, }, cli_args=[ f"--graphviz={self._graphviz_file}" @@ -345,9 +344,8 @@ def package(self): cmake = self._cmake_configure() cmake.install() - if self.options.use_project_cmake_config: - rm(self, "phasarConfig*.cmake", join("lib", "cmake", "phasar")) - rm(self, "*target*.cmake", join("lib", "cmake", "phasar")) + rm(self, "phasarConfig*.cmake", join("lib", "cmake", "phasar")) + rm(self, "*target*.cmake", join("lib", "cmake", "phasar")) self._write_build_info() From 0c9a7042a2c36a6e8df9796c3faa4fa3f42c6517 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Tue, 4 Feb 2025 00:01:38 +0100 Subject: [PATCH 12/18] doc(conan): update readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d41cb9719..35c60a16b 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,11 @@ To export the recipe and dependencies execute from repo root: - View exported`conan list "phasar/*"` - [Consume the package](https://docs.conan.io/2/tutorial/consuming_packages.html) +If you just want to use phasar-cli: +- `conan install --tool-requires phasar/... --build=missing -of .` +- `source conanbuild.sh` +- `phasar-cli --help` + ## Please help us to improve PhASAR You are using PhASAR and would like to help us in the future? Then please From ae0bd9a2e072f63ca5a0bb6a5d24eb4cf2b47b81 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Tue, 4 Feb 2025 00:10:42 +0100 Subject: [PATCH 13/18] clean(conan): minor review --- CMakeLists.txt | 9 +----- test_package/myphasartool.cpp | 58 ----------------------------------- 2 files changed, 1 insertion(+), 66 deletions(-) delete mode 100644 test_package/myphasartool.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 26fa490d4..304b04743 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -301,13 +301,6 @@ if(SQLite3_FOUND) else() set(PHASAR_HAS_SQLITE OFF) endif() -# Print all variables set by LLVM -get_cmake_property(all_variables VARIABLES) -foreach(var ${all_variables}) - if(var MATCHES "^LLVM_") - message(STATUS "${var} = ${${var}}") - endif() -endforeach() option(USE_LLVM_FAT_LIB "Link against libLLVM.so instead of the individual LLVM libraries if possible (default is OFF; always on if BUILD_SHARED_LIBS is ON)" OFF) @@ -324,7 +317,7 @@ if(PHASAR_USE_Z3 AND NOT PHASAR_IN_TREE) # as it lacks some functionality (such as z3::expr::simplify()) that we require find_package(Z3 4.7.1 REQUIRED) - if(NOT TARGET z3 ) + if(NOT TARGET z3) add_library(z3 IMPORTED SHARED) set_property(TARGET z3 PROPERTY IMPORTED_LOCATION ${Z3_LIBRARIES}) diff --git a/test_package/myphasartool.cpp b/test_package/myphasartool.cpp deleted file mode 100644 index f95f34ce2..000000000 --- a/test_package/myphasartool.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2017 Philipp Schubert. - * All rights reserved. This program and the accompanying materials are made - * available under the terms of LICENSE.txt. - * - * Contributors: - * Philipp Schubert and others - *****************************************************************************/ - -#include "phasar.h" - -#include -#include - -using namespace psr; - -int main(int Argc, const char **Argv) { - using namespace std::string_literals; - - if (Argc < 2 || !std::filesystem::exists(Argv[1]) || - std::filesystem::is_directory(Argv[1])) { - llvm::errs() << "myphasartool\n" - "A small PhASAR-based example program\n\n" - "Usage: myphasartool \n"; - return 1; - } - - std::vector EntryPoints = {"main"s}; - - HelperAnalyses HA(Argv[1], EntryPoints); - - if (const auto *F = HA.getProjectIRDB().getFunctionDefinition("main")) { - // print type hierarchy - HA.getTypeHierarchy().print(); - // print points-to information - HA.getAliasInfo().print(); - // print inter-procedural control-flow graph - HA.getICFG().print(); - - // IFDS template parametrization test - llvm::outs() << "Testing IFDS:\n"; - auto L = createAnalysisProblem(HA, EntryPoints); - IFDSSolver S(L, &HA.getICFG()); - auto IFDSResults = S.solve(); - IFDSResults.dumpResults(HA.getICFG()); - - // IDE template parametrization test - llvm::outs() << "Testing IDE:\n"; - auto M = createAnalysisProblem(HA, EntryPoints); - // Alternative way of solving an IFDS/IDEProblem: - auto IDEResults = solveIDEProblem(M, HA.getICFG()); - IDEResults.dumpResults(HA.getICFG()); - - } else { - llvm::errs() << "error: file does not contain a 'main' function!\n"; - } - return 0; -} From 6e775b48500ee76d51ede7a70ec2250b57e14aa9 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Tue, 4 Feb 2025 00:10:59 +0100 Subject: [PATCH 14/18] clean(conan): use link instead of copy --- test_package/myphasartool.cpp | 1 + 1 file changed, 1 insertion(+) create mode 120000 test_package/myphasartool.cpp diff --git a/test_package/myphasartool.cpp b/test_package/myphasartool.cpp new file mode 120000 index 000000000..89bf833f7 --- /dev/null +++ b/test_package/myphasartool.cpp @@ -0,0 +1 @@ +../tools/example-tool/myphasartool.cpp \ No newline at end of file From caaf9bb895c077e3292048f4c5aae029646b0415 Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Tue, 4 Feb 2025 11:07:51 +0100 Subject: [PATCH 15/18] clean(conan): fix pre-commit --- .pre-commit-config.yaml | 2 + cmake/phasar_macros.cmake | 10 ++-- conanfile.py | 39 +++++++------- utils/conan/clang/conanfile.py | 2 +- .../conan/clang/test_package/test_package.cpp | 5 +- utils/conan/llvm-core/conanfile.py | 2 +- .../llvm-core/test_package/test_package.cpp | 52 ++++++++----------- utils/conan/test_conan_build.sh | 4 +- 8 files changed, 56 insertions(+), 60 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fb9bed984..786e0aba3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,9 @@ repos: rev: v4.3.0 hooks: - id: trailing-whitespace + exclude: "^.*\\.patch$" - id: end-of-file-fixer + exclude: "^.*\\.patch$" - id: check-yaml - id: check-added-large-files - id: requirements-txt-fixer diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index 78dd7807a..e977abf97 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -68,17 +68,17 @@ function(generate_ll_file) message(STATUS "HINTS to find clang/clang++/opt: ${binary_hint_paths}") if ("${CMAKE_VERSION}" VERSION_LESS "3.25") # VALIDATOR requires it - + find_program(clang REQUIRED NAMES clang-14 clang HINTS ${binary_hint_paths}) find_program(clangcpp REQUIRED - NAMES clang++ + NAMES clang++ HINTS ${binary_hint_paths}) find_program(opt REQUIRED NAMES opt HINTS ${binary_hint_paths}) - + set(IS_VALID_VERSION "") validate_binary_version("IS_VALID_VERSION" "${clang}") if (NOT "${IS_VALID_VERSION}") @@ -99,8 +99,8 @@ function(generate_ll_file) VALIDATOR validate_binary_version) message(STATUS "found clang binary in \"${clang}\"") find_program(clangcpp REQUIRED - NAMES clang++ - HINTS ${binary_hint_paths} + NAMES clang++ + HINTS ${binary_hint_paths} VALIDATOR validate_binary_version) message(STATUS "found clang binary in \"${clangpp}\"") find_program(opt REQUIRED diff --git a/conanfile.py b/conanfile.py index e36825db5..0371d0138 100644 --- a/conanfile.py +++ b/conanfile.py @@ -118,14 +118,14 @@ class PhasarRecipe(ConanFile): # Binary configuration settings = "os", "compiler", "build_type", "arch" options = { - "with_z3": [True, False], - "shared": [True, False], + "with_z3": [True, False], + "shared": [True, False], "fPIC": [True, False], "tests": [True, False], } default_options = { - "with_z3": True, - "shared": False, + "with_z3": True, + "shared": False, "fPIC": True, "tests": False, } @@ -141,7 +141,7 @@ def _parse_gitignore(self, folder, additional_exclusions = [], invert=False): inclusions = f"!{exc}" else: exclusions = additional_exclusions - + with open(f'{folder}/.gitignore', 'r') as file: for line in file: line = line.strip() @@ -154,7 +154,7 @@ def _parse_gitignore(self, folder, additional_exclusions = [], invert=False): inclusions.append("!" + line) else: exclusions.append(line) - + if invert: return inclusions else: @@ -162,10 +162,10 @@ def _parse_gitignore(self, folder, additional_exclusions = [], invert=False): def export_sources(self): exclusions = self._parse_gitignore(".", [ - "test_package", - "utils", - "img", - "githooks", + "test_package", + "utils", + "img", + "githooks", "external" ]) @@ -185,7 +185,7 @@ def _info_file(self): if self.export_folder is None: return None return PurePosixPath(self.export_folder) / "info.json" - + def _read_info(self): if self._info_file is not None and exists(self._info_file): with open(self._info_file, encoding="utf-8") as fp: @@ -194,12 +194,12 @@ def _read_info(self): return { "version": None, } - + def _write_info(self, info): if self._info_file is not None: with open(self._info_file, "w", encoding="utf-8") as fp: json.dump(info, fp, indent=2) - + def set_version(self): if self.version is not None: return @@ -240,14 +240,14 @@ def requirements(self): self.requires("z3/[>=4.7.1 <5]") llvm_options["with_z3"] = True self.requires("llvm-core/14.0.6@secure-software-engineering", transitive_libs=True, transitive_headers=True, options=llvm_options) - + def build_requirements(self): self.tool_requires("cmake/[>=3.25.0 <4.0.0]") # find_program validator self.tool_requires("ninja/[>=1.9.0 <2.0.0]") if self.options.tests: self.test_requires("openssl/[>2 <4]") self.test_requires("gtest/1.14.0") - + def configure(self): if self.options.shared: self.options.rm_safe("fPIC") @@ -282,7 +282,7 @@ def _cmake_configure(self): ] ) return cmake - + def _handle_graphviz(self): exclude_patterns = [ "LLVMTableGenGlobalISel.*", @@ -322,7 +322,7 @@ def _write_build_info(self): # maybe process original config cmake_config = Path(self.package_folder / self._cmake_module_path / "phasarConfig.cmake").read_text("utf-8") components = components_from_dotfile(load(self, self._graphviz_file)) - + build_info = { "components": components, } @@ -341,7 +341,7 @@ def package_id(self): def package(self): copy(self, "LICENSE.txt", self.source_folder, join(self.package_folder, "licenses")) - + cmake = self._cmake_configure() cmake.install() rm(self, "phasarConfig*.cmake", join("lib", "cmake", "phasar")) @@ -359,7 +359,6 @@ def package_info(self): for component_name, data in components.items(): self.cpp_info.components[component_name].set_property("cmake_target_name", component_name) - self.cpp_info.components[component_name].libs = [component_name] if component_name not in interfaces else [] + self.cpp_info.components[component_name].libs = [component_name] if component_name not in interfaces else [] self.cpp_info.components[component_name].requires = data["requires"] self.cpp_info.components[component_name].system_libs = data["system_libs"] - diff --git a/utils/conan/clang/conanfile.py b/utils/conan/clang/conanfile.py index 49df249de..5205624bd 100644 --- a/utils/conan/clang/conanfile.py +++ b/utils/conan/clang/conanfile.py @@ -60,7 +60,7 @@ def _compilers_minimum_version(self): "msvc": "191", "Visual Studio": "15", } - + def export_sources(self): export_conandata_patches(self) diff --git a/utils/conan/clang/test_package/test_package.cpp b/utils/conan/clang/test_package/test_package.cpp index 361050c0d..20dbd197c 100644 --- a/utils/conan/clang/test_package/test_package.cpp +++ b/utils/conan/clang/test_package/test_package.cpp @@ -1,4 +1,5 @@ -// A basic clang libtooling example from https://clang.llvm.org/docs/LibTooling.html +// A basic clang libtooling example from +// https://clang.llvm.org/docs/LibTooling.html // Declares clang::SyntaxOnlyAction. #include "clang/Frontend/FrontendActions.h" @@ -28,7 +29,7 @@ int main(int argc, const char **argv) { llvm::errs() << ExpectedParser.takeError(); return 1; } - CommonOptionsParser& OptionsParser = ExpectedParser.get(); + CommonOptionsParser &OptionsParser = ExpectedParser.get(); ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); return Tool.run(newFrontendActionFactory().get()); diff --git a/utils/conan/llvm-core/conanfile.py b/utils/conan/llvm-core/conanfile.py index 6bfc76aaf..d06658e02 100644 --- a/utils/conan/llvm-core/conanfile.py +++ b/utils/conan/llvm-core/conanfile.py @@ -131,7 +131,7 @@ def _compilers_minimum_version(self): "msvc": "191", "Visual Studio": "15", } - + def export_sources(self): export_conandata_patches(self) diff --git a/utils/conan/llvm-core/test_package/test_package.cpp b/utils/conan/llvm-core/test_package/test_package.cpp index e5de3a64a..fd234d8a4 100644 --- a/utils/conan/llvm-core/test_package/test_package.cpp +++ b/utils/conan/llvm-core/test_package/test_package.cpp @@ -1,38 +1,32 @@ -#include -#include +#include + #include -#include +#include +#include #include -#include +#include #include +#include -#include - - -int main(int argc, char const* argv[]) { - if (argc < 2) - return 0; +int main(int argc, char const *argv[]) { + if (argc < 2) + return 0; - llvm::InitializeNativeTarget(); - llvm::SMDiagnostic smd; - llvm::LLVMContext context; - std::string error; + llvm::InitializeNativeTarget(); + llvm::SMDiagnostic smd; + llvm::LLVMContext context; + std::string error; - llvm::EngineBuilder engine_builder{ - llvm::parseIRFile(argv[1], smd, context) - }; - engine_builder.setEngineKind(llvm::EngineKind::Interpreter); - engine_builder.setErrorStr(&error); + llvm::EngineBuilder engine_builder{llvm::parseIRFile(argv[1], smd, context)}; + engine_builder.setEngineKind(llvm::EngineKind::Interpreter); + engine_builder.setErrorStr(&error); - auto execution_engine = std::unique_ptr( - engine_builder.create() - ); - execution_engine->runStaticConstructorsDestructors(false); + auto execution_engine = + std::unique_ptr(engine_builder.create()); + execution_engine->runStaticConstructorsDestructors(false); - auto test_function = execution_engine->FindFunctionNamed("test"); - auto result = execution_engine->runFunction( - test_function, - llvm::ArrayRef() - ); - return result.IntVal.getSExtValue(); + auto test_function = execution_engine->FindFunctionNamed("test"); + auto result = execution_engine->runFunction( + test_function, llvm::ArrayRef()); + return result.IntVal.getSExtValue(); } diff --git a/utils/conan/test_conan_build.sh b/utils/conan/test_conan_build.sh index 25cd1a896..99992731a 100755 --- a/utils/conan/test_conan_build.sh +++ b/utils/conan/test_conan_build.sh @@ -5,10 +5,10 @@ set -euo pipefail ( cd "$(dirname "$0")" cd ../.. - conan create . --version dev --build=missing -s build_type=RelWithDebInfo + conan create . --version dev --build=missing -s build_type=RelWithDebInfo cd test_package/build/ mkdir -p Debug/generators cd Debug/generators conan install -of . --requires phasar/dev --build=missing -s build_type=Release -g VirtualRunEnv -g CMakeDeps conan install -of . --requires phasar/dev --build=missing -s build_type=Debug -g VirtualRunEnv -g CMakeDeps -) \ No newline at end of file +) From c4ba186857182753084f0fb191513a1cf2757dce Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Wed, 5 Feb 2025 17:41:09 +0100 Subject: [PATCH 16/18] deploy(conan): fix ci? libclang-cpp.so forced linking to libLLVM.so --- README.md | 2 +- cmake/add_llvm.cmake | 6 +++++- cmake/phasar_macros.cmake | 38 ++++++++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 35c60a16b..6406339c2 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ To export the recipe and dependencies execute from repo root: - `conan export utils/conan/llvm-core/ --version 14.0.6 --user secure-software-engineering` - `conan export utils/conan/clang/ --version 14.0.6 --user secure-software-engineering` - `conan export .` -- View exported`conan list "phasar/*"` +- View exported `conan list "phasar/*"` - [Consume the package](https://docs.conan.io/2/tutorial/consuming_packages.html) If you just want to use phasar-cli: diff --git a/cmake/add_llvm.cmake b/cmake/add_llvm.cmake index 8fae6dc4b..146573762 100644 --- a/cmake/add_llvm.cmake +++ b/cmake/add_llvm.cmake @@ -59,7 +59,11 @@ macro(add_clang) find_package(Clang REQUIRED) set(CLANG_LIBRARY clangCodeGen clangTooling) elseif(NOT PHASAR_IN_TREE) - find_library(CLANG_LIBRARY NAMES clang-cpp libclang-cpp HINTS ${LLVM_LIBRARY_DIRS}) + if (USE_LLVM_FAT_LIB) + find_library(CLANG_LIBRARY NAMES clang-cpp libclang-cpp HINTS ${LLVM_LIBRARY_DIRS}) + else() + find_library(CLANG_LIBRARY NAMES clangCodeGen clangTooling HINTS ${LLVM_LIBRARY_DIRS}) + endif() if(${CLANG_LIBRARY} STREQUAL "CLANG_LIBRARY-NOTFOUND") set(NEED_LIBCLANG_COMPONENT_LIBS ON) endif() diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index e977abf97..67ac0f573 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -62,52 +62,66 @@ function(generate_ll_file) if (NOT clang) # Conan deps are available in in PATH foreach(hint "${LLVM_TOOLS_BINARY_DIR}" "${Clang_INCLUDE_DIR}/../bin" "${LLVM_INCLUDE_DIR}/../bin" "/usr/local/llvm-14/bin") - cmake_path(NORMAL_PATH hint OUTPUT_VARIABLE hint) + if ("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.20") + cmake_path(NORMAL_PATH hint OUTPUT_VARIABLE hint) + endif() list(APPEND binary_hint_paths "${hint}") endforeach() message(STATUS "HINTS to find clang/clang++/opt: ${binary_hint_paths}") if ("${CMAKE_VERSION}" VERSION_LESS "3.25") # VALIDATOR requires it - + message(WARNING "I would prefer CMake >= 3.25 but I will try my best to resolve deps.") find_program(clang REQUIRED NAMES clang-14 clang HINTS ${binary_hint_paths}) find_program(clangcpp REQUIRED - NAMES clang++ + NAMES clang++-14 clang++ HINTS ${binary_hint_paths}) find_program(opt REQUIRED - NAMES opt + NAMES opt-14 opt HINTS ${binary_hint_paths}) set(IS_VALID_VERSION "") validate_binary_version("IS_VALID_VERSION" "${clang}") if (NOT "${IS_VALID_VERSION}") - message(FATAL_ERROR "Couldn't find clang in version 14") + set(clang "") endif() validate_binary_version("IS_VALID_VERSION" "${clangcpp}") if (NOT "${IS_VALID_VERSION}") - message(FATAL_ERROR "Couldn't find clang++ in version 14") + set(clangcpp "") endif() validate_binary_version("IS_VALID_VERSION" "${opt}") if (NOT "${IS_VALID_VERSION}") - message(FATAL_ERROR "Couldn't find opt in version 14") + set(opt "") endif() else() find_program(clang REQUIRED NAMES clang-14 clang HINTS ${binary_hint_paths} VALIDATOR validate_binary_version) - message(STATUS "found clang binary in \"${clang}\"") find_program(clangcpp REQUIRED - NAMES clang++ + NAMES clang++-14 clang++ HINTS ${binary_hint_paths} VALIDATOR validate_binary_version) - message(STATUS "found clang binary in \"${clangpp}\"") find_program(opt REQUIRED - NAMES opt + NAMES opt-14 opt HINTS ${binary_hint_paths} VALIDATOR validate_binary_version) - message(STATUS "found clang binary in \"${opt}\"") + endif() + if ("${clang}" STREQUAL "") + message(FATAL_ERROR "Couldn't find clang in version 14") + else() + message(STATUS "found clang binary in \"${clang}\"") + endif() + if ("${clangcpp}" STREQUAL "") + message(FATAL_ERROR "Couldn't find clang++ in version 14") + else() + message(STATUS "found clang++ binary in \"${clangcpp}\"") + endif() + if ("${opt}" STREQUAL "") + message(FATAL_ERROR "Couldn't find opt in version 14") + else() + message(STATUS "found opt binary in \"${opt}\"") endif() endif() From 26a9f58cb88f53f094e1adcaf40e2db018c5ed55 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Thu, 6 Feb 2025 18:27:19 +0100 Subject: [PATCH 17/18] Use PHASAR_LLVM_VERSION to refer to the llvm version in the cmake configuration --- cmake/phasar_macros.cmake | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index 2a88fb28d..ce9d6f6b8 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -46,7 +46,7 @@ function(validate_binary_version result item) OUTPUT_STRIP_TRAILING_WHITESPACE ) - string(REGEX MATCH " version 14\\." match "${output}") + string(REGEX MATCH " version ${PHASAR_LLVM_VERSION}\\." match "${output}") if (match) set(${result} TRUE PARENT_SCOPE) else() @@ -61,7 +61,7 @@ function(generate_ll_file) if (NOT clang) # Conan deps are available in in PATH - foreach(hint "${LLVM_TOOLS_BINARY_DIR}" "${Clang_INCLUDE_DIR}/../bin" "${LLVM_INCLUDE_DIR}/../bin" "/usr/local/llvm-14/bin") + foreach(hint "${LLVM_TOOLS_BINARY_DIR}" "${Clang_INCLUDE_DIR}/../bin" "${LLVM_INCLUDE_DIR}/../bin" "/usr/local/llvm-${PHASAR_LLVM_VERSION}/bin") if ("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.20") cmake_path(NORMAL_PATH hint OUTPUT_VARIABLE hint) endif() @@ -72,54 +72,54 @@ function(generate_ll_file) if ("${CMAKE_VERSION}" VERSION_LESS "3.25") # VALIDATOR requires it message(WARNING "I would prefer CMake >= 3.25 but I will try my best to resolve deps.") find_program(clang REQUIRED - NAMES clang-14 clang + NAMES clang-${PHASAR_LLVM_VERSION} clang HINTS ${binary_hint_paths}) find_program(clangcpp REQUIRED - NAMES clang++-14 clang++ + NAMES clang++-${PHASAR_LLVM_VERSION} clang++ HINTS ${binary_hint_paths}) find_program(opt REQUIRED - NAMES opt-14 opt + NAMES opt-${PHASAR_LLVM_VERSION}4 opt HINTS ${binary_hint_paths}) set(IS_VALID_VERSION "") - validate_binary_version("IS_VALID_VERSION" "${clang}") + validate_binary_version(IS_VALID_VERSION "${clang}") if (NOT "${IS_VALID_VERSION}") set(clang "") endif() - validate_binary_version("IS_VALID_VERSION" "${clangcpp}") + validate_binary_version(IS_VALID_VERSION "${clangcpp}") if (NOT "${IS_VALID_VERSION}") set(clangcpp "") endif() - validate_binary_version("IS_VALID_VERSION" "${opt}") + validate_binary_version(IS_VALID_VERSION "${opt}") if (NOT "${IS_VALID_VERSION}") set(opt "") endif() else() find_program(clang REQUIRED - NAMES clang-14 clang + NAMES clang-${PHASAR_LLVM_VERSION} clang HINTS ${binary_hint_paths} VALIDATOR validate_binary_version) find_program(clangcpp REQUIRED - NAMES clang++-14 clang++ + NAMES clang++-${PHASAR_LLVM_VERSION} clang++ HINTS ${binary_hint_paths} VALIDATOR validate_binary_version) find_program(opt REQUIRED - NAMES opt-14 opt + NAMES opt-${PHASAR_LLVM_VERSION} opt HINTS ${binary_hint_paths} VALIDATOR validate_binary_version) endif() if ("${clang}" STREQUAL "") - message(FATAL_ERROR "Couldn't find clang in version 14") + message(FATAL_ERROR "Couldn't find clang in version ${PHASAR_LLVM_VERSION}") else() message(STATUS "found clang binary in \"${clang}\"") endif() if ("${clangcpp}" STREQUAL "") - message(FATAL_ERROR "Couldn't find clang++ in version 14") + message(FATAL_ERROR "Couldn't find clang++ in version ${PHASAR_LLVM_VERSION}") else() message(STATUS "found clang++ binary in \"${clangcpp}\"") endif() if ("${opt}" STREQUAL "") - message(FATAL_ERROR "Couldn't find opt in version 14") + message(FATAL_ERROR "Couldn't find opt in version ${PHASAR_LLVM_VERSION}") else() message(STATUS "found opt binary in \"${opt}\"") endif() From 4f11dc5ab74261234c42451407034a8a790d56aa Mon Sep 17 00:00:00 2001 From: Lucas Briese Date: Thu, 6 Feb 2025 19:40:53 +0100 Subject: [PATCH 18/18] deploy(conan): fix review --- .github/CODEOWNERS | 3 +++ cmake/phasar_macros.cmake | 16 +++++++++------- conanfile.py | 1 - test_package/example.ll | 8 ++++---- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3e7412921..8eb739509 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -32,3 +32,6 @@ Dockerfile @janniclas /include/phasar/Utils/OnTheFlyAnalysisPrinter.h @sritejakv /include/phasar/PhasarLLVM/Utils/SourceMgrPrinter.h @sritejakv /lib/PhasarLLVM/Utils/SourceMgrPrinter.cpp @sritejakv + +/conanfile.py @jusito +/utils/conan/ @jusito diff --git a/cmake/phasar_macros.cmake b/cmake/phasar_macros.cmake index ce9d6f6b8..4c3d796db 100644 --- a/cmake/phasar_macros.cmake +++ b/cmake/phasar_macros.cmake @@ -159,13 +159,15 @@ function(generate_ll_file) set(GEN_C_FLAGS -fno-discard-value-names -emit-llvm -S -w) set(GEN_CMD_COMMENT "[LL]") - # uncomment with branch f-TestingAPIChanges - # if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) - # list(APPEND GEN_CXX_FLAGS -Xclang -no-opaque-pointers) - # endif() - # if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15) - # list(APPEND GEN_C_FLAGS -Xclang -no-opaque-pointers) - # endif() + string(REGEX MATCH "clang\\+*-?[0-9]*$" compiler "${CMAKE_CXX_COMPILER}") + if (compiler) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) + list(APPEND GEN_CXX_FLAGS -Xclang -no-opaque-pointers) + endif() + if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15) + list(APPEND GEN_C_FLAGS -Xclang -no-opaque-pointers) + endif() + endif() if(GEN_LL_MEM2REG) list(APPEND GEN_CXX_FLAGS -Xclang -disable-O0-optnone) diff --git a/conanfile.py b/conanfile.py index 0371d0138..8ce3c4047 100644 --- a/conanfile.py +++ b/conanfile.py @@ -110,7 +110,6 @@ class PhasarRecipe(ConanFile): # Optional metadata license = "MIT license" - author = " " url = "https://github.com/secure-software-engineering/phasar" description = "A LLVM-based static analysis framework. " topics = ("LLVM", "PhASAR", "SAST") diff --git a/test_package/example.ll b/test_package/example.ll index 3ed2ea3e4..9e732545b 100644 --- a/test_package/example.ll +++ b/test_package/example.ll @@ -1,5 +1,5 @@ -; ModuleID = '/home/lucas/git/itst-develop/02_sa/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c' -source_filename = "/home/lucas/git/itst-develop/02_sa/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c" +; ModuleID = 'test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c' +source_filename = "test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c" target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -103,7 +103,7 @@ attributes #4 = { nounwind } !llvm.ident = !{!9} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git d28af7c654d8db0b68c175db5ce212d74fb5e9bc)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) -!1 = !DIFile(filename: "/home/lucas/git/itst-develop/02_sa/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c", directory: "/home/lucas/git/itst-develop/02_sa/build/intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach") +!1 = !DIFile(filename: "test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c", directory: "test/resources/llvm_test_code/two_analyses_approach") !2 = !{} !3 = !{!4} !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) @@ -113,7 +113,7 @@ attributes #4 = { nounwind } !8 = !{i32 1, !"wchar_size", i32 4} !9 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git d28af7c654d8db0b68c175db5ce212d74fb5e9bc)"} !10 = distinct !DISubprogram(name: "fun1", scope: !11, file: !11, line: 6, type: !12, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) -!11 = !DIFile(filename: "intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c", directory: "/home/lucas/git/itst-develop/02_sa") +!11 = !DIFile(filename: "intellisec-sast/analysis/test/resources/llvm_test_code/two_analyses_approach/ta_test_inter_true_positive.c", directory: "/home/user/git/itst/") !12 = !DISubroutineType(types: !13) !13 = !{null, !4, !5} !14 = !DILocalVariable(name: "v", arg: 1, scope: !10, file: !11, line: 6, type: !4)