-
Notifications
You must be signed in to change notification settings - Fork 479
Build, CI, Formatting, API & SVFG Builder Improvements #1697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1697 +/- ##
==========================================
- Coverage 63.70% 63.67% -0.04%
==========================================
Files 244 244
Lines 25962 25988 +26
Branches 4565 4581 +16
==========================================
+ Hits 16539 16547 +8
- Misses 9423 9441 +18
🚀 New features to boost your workflow:
|
|
Thanks for the contribution. Could you split this pull request into two?
I had a quick look at 2, all look good, and should be ready to merge. 1 looks a bit complicated and I will have to go through it separately. Cheers |
Sure, give me a bit to figure out what the easiest way to do this would be!
Great, happy to hear!
Makes sense. I did make sure to not break any backwards compatibility; all current ways of using SVF should continue to work unchanged. The only difference is that the exported CMake package now properly handles relocatability and dependency inheritance. For example, the current CMake package doesn't properly expose dependencies and necessary ABI flags on the actual targets. As a result, linking against SVF's package after finding system instances (e.g., with For example, say I want to use system-wide installations of Z3 & LLVM to build & link SVF against. I could install Z3 & LLVM like this: # Z3 from official Ubuntu repositories
> sudo apt install z3 libz3-4 libz3-dev
# Ubuntu 24.04 (Noble) has LLVM-16 in the official repos as well
> sudo apt install llvm-16 llvm-16-dev llvm-16-tools \
clang-16 libclang-16-dev libclang-rt-16-dev \
lld-16 liblld-16 liblld-16-dev \
...This would install these libraries in These changes support using SVF in the same way. For example, I can build & install SVF globally like this: > git clone https://github.com/SVF-tools/SVF.git ./SVF
> cd SVF
> cmake -S ./ \
-G "Ninja" \
-B Release-build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DSVF_ENABLE_ASSERTIONS=ON \
-DSVF_EXPORT_DYNAMIC=ON \
-DBUILD_SHARED_LIBS=ON \
-DSVF_DEBUG_INFO=ON \
-DSVF_USE_LLD=ON
> cmake --build Release-build
> cmake --install Release-build [--install-prefix=/some/other/prefix]This would install SVF's headers, CMake package, etc. to the chosen prefix so that the tools end up in places like
cmake_minimum_required(VERSION 3.28)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(Foo CXX)
add_executable(foo foo.cpp)
find_package(SVF 3.0 REQUIRED CONFIG)
target_link_libraries(foo PRIVATE SVF::SvfCore SVF::SvfLLVM)
install(TARGETS foo RUNTIME DESTINATION bin)
#include <MSSA/SVFGBuilder.h>
#include <SVF/Graphs/SVFG.h>
#include <SVF/SVF-LLVM/LLVMModule.h>
#include <SVF/SVF-LLVM/SVFIRBuilder.h>
#include <SVF/Util/CommandLine.h>
#include <SVF/Util/Options.h>
#include <SVF/WPA/Andersen.h>
#include <cstdlib>
#include <string>
#include <vector>
using namespace llvm;
using namespace std;
using namespace SVF;
int main(int argc, char **argv) {
std::vector<std::string> modNameVec = OptionBase::parseOptions(
argc, argv, "bitcodes", "[options] <bitcode...>");
if (Options::WriteAnder() == "ir_annotator")
LLVMModuleSet::preProcessBCs(modNameVec);
LLVMModuleSet::buildSVFModule(modNameVec);
SVFIR *pag = SVFIRBuilder().build();
Andersen *ander = AndersenWaveDiff::createAndersenWaveDiff(pag);
SVFG *svfg = SVFGBuilder().buildFullSVFG(ander);
svfg->dump("input");
AndersenWaveDiff::releaseAndersenWaveDiff();
SVF::LLVMModuleSet::releaseLLVMModuleSet();
SVFIR::releaseSVFIR();
llvm::llvm_shutdown();
return EXIT_SUCCESS;
}I could then build, install, and run my tool like this: > cmake -G "Ninja" -B build
> cmake --build build
> cmake --install build --prefix $(pwd)/install
> ./install/bin/foo some/example/bitcode.bcThe Of course, since the Moreover, after the Moreover, this keeps the dependencies "separate", ensuring only the I hope this clarifies the changes & use-case a bit more! As I said, I'd be happy to update the Wiki page to describe how to build, install, and use SVF and its dependencies like this, as well as write a new Wiki page describing how to use SVF within the default LLVM clang pass-pipeline! Would you still like me to split this pull request (no problem), or should I leave it combined if this makes enough sense to merge as-is? |
Numerous fixes and improvements to the overall build system. Core changes include: - Moved CMake files (templates, input, etc.) into dedicated `cmake` subdirectory - Fixed relocatability of install tree (support for `cmake --install <build-dir> --install-prefix=<prefix>`) - Relocatable packages no longer depend on absolute paths of dependencies (i.e., Z3, LLVM) - SVF root, source, build, and install directories now exposed properly & correctly handle relocations - Required ABI flags of users (e.g., minimum C++ standard, PIC, etc.) now exposed through interface library (invisible) - Exported `pkconfig` package defines the core required flags - Explicit support for using SVF in-tree (i.e., building SVF from another project's `CMakeLists.txt` with `add_subdirectory(SVF)`) - Added IPO compiler support check when LTO is enabled (trying to use LTO if not supported throws a fatal error) - Required ABI flags of dependencies (i.e., Z3, LLVM) are now exposed publically on the CMake package's libraries (i.e., `SvfCore` and `SvfLLVM`; so they are inherited when using SVF with `find_package(SVF)` and `target_link_libraries(myLib <PUBLIC|PRIVATE|INTERFACE> SVF::Core SVF::LLVM)`) - Exposing SVF version to parent (i.e., updating `SVF_VERSION` defined in parent scope when adding SVF with `add_subdirectory(SVF)`) now conditional on there being a parent project to suppress warnings when not using SVF this way
The current GitHub Workflow coverage test removes coverage information from certain files (i.e., with `lcov --remove coverage.info '/usr/*' --output-file coverage.info`). If the given directory (e.g., `/usr/*`) contains no files with coverage information, trying to remove this coverage information throws an error. The current workflow only adds `--ignore-errors unused` for the files with coverage information in `${{github.workspace}}/svf/include/FastCluster/*`, but not for the other directories. As this information should be removed anyway (also for the other directories), not having coverage information to begin with shouldn't be seen as an error. This commit applies the `--ignore-errors unused` flag consistently to the other `lcov --remove ...` invocations.
While there are formatting description files for C/C++ (i.e., `.clang-format`), no equivalent formatting specification exists for CMake (to automatically format CMake files (e.g., `CMakeLists.txt`) consistently with `cmake-format`). This commit adds such a format description to ensure all CMake files are formatted consistently.
Most `get...()` functions have `has...()` equivalents (e.g., `getDefSVFGNode()` and `hasDefSVFGNode()`). However, certain getters (e.g., `getLLVMValue()`, `getLHSTopLevelPtr()` had no such existence-checking counterparts. This commit adds a number of these checking functions in cases where they were missing. Note that these are for cases where the getters fail an assertion when no valid value exists. Cases where the getter simply returns a null-pointer on failure to find any corresponding values (e.g., `ICFG::getFunEntryBlock()`, `ICFG::getFunExitBlock()`, etc.), so a null-check can be used to catch cases where the getter fails to get any corresponding object, and thus don't need a corresponding existence checker. To avoid changing the current behaviour of the assertions and getters, I added additional existence-checking functions. This does mean the container will be searched twice (once in the existence-check and then again in the getter itself) and thus wastes performance. To avoid this, all current getters could be modified so that all getters return null-pointers on failures, but I didn't want to make such an intrusive change in this commit.
…istent with other WPA implementations)
Currently, most WPA implementations (e.g., `AndersenWaveDiff`) expose read-only functions (e.g., `printStat()`, `dumpTopLevelPtsTo()`, etc.) publically, as well as "constructors" like `solveAndWritePtsToFile()`, `readPtsFromFile()`, etc. However, `VersionedFlowSensitive` is the only one to mark these functions as `private`/`protected`. This makes it annoying to use polymorphism over the underlying PTA base class (i.e., `BVDataPTAImpl`) and the overridden virtual functions. This commit fixes that by marking these functions as public in the `VersionedFlowSensitive` WPA class.
This change allows me to use polymorphism to conveniently try different WPA backends like this:
```
SVF::BVDataPTAImpl *pta = nullptr;
switch(getChosenBackend()) {
case Andersen_BASE:
pta = new Andersen(...);
break;
case VFS_WPA:
pta = new VersionedFlowSensitive(...);
break;
default:
break;
}
```
…existing results The current `SVFGBuilder` optimises the SVFG based on the command-line argument. However, when using SVF as a library, this is inconvenient. This commit changes the builder to use an additional flag to control optimisation behaviour. Moreover, this commit fixes the reading/writing issues for optimised SVFGs. Currently, the writing happens post-optimisation, which causes the reading step to fail due to missing/unexpected nodes. This commit also ensures the *unoptimised SVFG* is written to a file *prior to optimising it*, and reads an unoptimised SVFG from a file and then optimises it. This fixes these crashing issues.
def7c04 to
d25a348
Compare
|
Rebased from the current upstream's head to make merging easier. @yuleisui, let me know if you'd still like me to separate this pull request or if my previous comment sufficiently clarified my intent/use-case and you want to merge it as-is! |
Thanks, and could you separate the pull request? I can merge your "non-Build System" one first. |
📝 Overview
This PR consolidates six orthogonal areas of work into one release:
cmake-formatconfig for consistent styling & formattinghas…()checks alongside existing gettersFor full details on each change, see the linked commits below.
If you'd like, I could add a section to the setup guide wiki page to explain installing & using SVF's CMake packages. Additionally, I could also add a new page detailing how to use SVF from within an out-of-tree LLVM pass directly from the default clang pass-pipeline (i.e., analyse & possibly modify a module using information from SVF's analyses during regular compilation (by simply adding a
--Wl,--load-pass-plugin=libSVFUser.so)?🚀 Highlights
--ignore-errors unusedon alllcov --removecmake-formatspec for automatic stylinghas…()functions for previously unchecked gettersVersionedFlowSensitive⚙️ Detailed Changes
1️⃣ Build System ([583bff0])
cmake/cmake --install … --install-prefix=<prefix>).pcwith core flags (less complete than the CMake package)add_subdirectory(SVF)now works transparentlySVF::Core&SVF::LLVMSVF_VERSIONin parent scope when parent CMake project exists2️⃣ CI/Workflow Fix ([96c021b])
--ignore-errors unusedto alllcov --remove …calls/usr/*or other paths3️⃣ Automated CMake Formatting ([0bc1472])
.cmake-format.pysocmake-formatcan lint & format all CMake filesCMakeLists.txt,*.cmake, etc.4️⃣ Existence-Check APIs ([ce288cf])
hasLLVMValue(),hasLHSTopLevelPtr(), etc., for getters that assert on missing entries5️⃣ WPA Backend Polymorphism ([93446f6])
VersionedFlowSensitive’sprintStat(),dumpTopLevelPtsTo(),solveAndWritePtsToFile(),readPtsFromFile(), etc., as public6️⃣ Optimised SVFG Read/Write Fix ([def7c04])