diff options
| author | Glenn Smith <glenn@vector35.com> | 2024-08-21 16:33:45 -0400 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2024-08-22 15:24:06 -0400 |
| commit | 7903373186110579117540026871209311277199 (patch) | |
| tree | 15b92d801d630f097d67cc244fe483c4c8afb07d | |
| parent | 183a842161b08fe51c92cf7cef5b11ba3d1f03fa (diff) | |
CMake: Generate a stub header for linking plugins without an install
This patch has existed on the cpp sample plugin for a while, just finally merging it into api.
| -rw-r--r-- | CMakeLists.txt | 59 | ||||
| -rw-r--r-- | cmake/generate_stubs.py | 121 |
2 files changed, 167 insertions, 13 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 57ed627e..369f6e05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,10 +33,41 @@ add_library(binaryninjaapi STATIC ${BN_API_SOURCES}) target_include_directories(binaryninjaapi PUBLIC ${PROJECT_SOURCE_DIR}) -find_package(BinaryNinjaCore REQUIRED) -target_link_libraries(binaryninjaapi PUBLIC ${BinaryNinjaCore_LIBRARIES}) -target_link_directories(binaryninjaapi PUBLIC ${BinaryNinjaCore_LIBRARY_DIRS}) -target_compile_definitions(binaryninjaapi PUBLIC ${BinaryNinjaCore_DEFINITIONS}) +find_package(BinaryNinjaCore) +if(BinaryNinjaCore_FOUND) + target_link_libraries(binaryninjaapi PUBLIC ${BinaryNinjaCore_LIBRARIES}) + target_link_directories(binaryninjaapi PUBLIC ${BinaryNinjaCore_LIBRARY_DIRS}) + target_compile_definitions(binaryninjaapi PUBLIC ${BinaryNinjaCore_DEFINITIONS}) +else() + if(APPLE) + target_link_options(binaryninjaapi PUBLIC -undefined dynamic_lookup) + elseif(MSVC) + # Generate stubs.cpp with implementations of all the BNAPI functions + execute_process(COMMAND python ${PROJECT_SOURCE_DIR}/cmake/generate_stubs.py ${PROJECT_SOURCE_DIR}/binaryninjacore.h ${PROJECT_BINARY_DIR}/stubs) + + # Compile those stubs into a stub library we can use to fool the linker + add_library(binaryninjacore SHARED ${PROJECT_BINARY_DIR}/stubs/stubs.cpp) + set_target_properties(binaryninjacore + PROPERTIES OUTPUT_NAME binaryninjacore + SOVERSION 1 + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/stubs + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/stubs + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/stubs + ) + target_include_directories(binaryninjacore PUBLIC ${PROJECT_SOURCE_DIR}) + + # Be sure to only link against the stubs archive file + add_dependencies(binaryninjaapi binaryninjacore) + if(${CMAKE_GENERATOR} MATCHES "^Visual Studio") + # Visual Studio's generator adds the config to the file path + target_link_libraries(binaryninjaapi PUBLIC "$<TARGET_PROPERTY:binaryninjacore,ARCHIVE_OUTPUT_DIRECTORY>/$<CONFIG>/$<TARGET_PROPERTY:binaryninjacore,OUTPUT_NAME>.lib") + else() + target_link_libraries(binaryninjaapi PUBLIC "$<TARGET_PROPERTY:binaryninjacore,ARCHIVE_OUTPUT_DIRECTORY>/$<TARGET_PROPERTY:binaryninjacore,OUTPUT_NAME>.lib") + endif() + else() + target_link_options(binaryninjaapi PUBLIC "LINKER:--allow-shlib-undefined") + endif() +endif() if(BN_REF_COUNT_DEBUG) target_compile_definitions(binaryninjaapi PUBLIC BN_REF_COUNT_DEBUG) @@ -94,16 +125,18 @@ function(bn_install_plugin target) list(APPEND CMAKE_MODULE_PATH "${BN_API_SOURCE_DIR}/cmake") # BinaryNinjaCore has the user plugins dir define that we want - find_package(BinaryNinjaCore REQUIRED) - if(WIN32) - install(TARGETS ${target} RUNTIME - DESTINATION ${BinaryNinjaCore_USER_PLUGINS_DIR}) + find_package(BinaryNinjaCore) + if(BinaryNinjaCore_FOUND) + if(WIN32) + install(TARGETS ${target} RUNTIME + DESTINATION ${BinaryNinjaCore_USER_PLUGINS_DIR}) - install(FILES $<TARGET_PDB_FILE:${target}> - DESTINATION ${BinaryNinjaCore_USER_PLUGINS_DIR} OPTIONAL) - else() - install(TARGETS ${target} LIBRARY - DESTINATION ${BinaryNinjaCore_USER_PLUGINS_DIR}) + install(FILES $<TARGET_PDB_FILE:${target}> + DESTINATION ${BinaryNinjaCore_USER_PLUGINS_DIR} OPTIONAL) + else() + install(TARGETS ${target} LIBRARY + DESTINATION ${BinaryNinjaCore_USER_PLUGINS_DIR}) + endif() endif() endif() endfunction() diff --git a/cmake/generate_stubs.py b/cmake/generate_stubs.py new file mode 100644 index 00000000..48ab574f --- /dev/null +++ b/cmake/generate_stubs.py @@ -0,0 +1,121 @@ +# Copyright (c) 2015-2024 Vector 35 Inc +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Based on BinExport + +# Copyright 2011-2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os +import re +import sys + +parser = argparse.ArgumentParser(sys.argv[0]) +parser.add_argument("core_header") +parser.add_argument("build_dir") + +options = parser.parse_args() + +print(f"GENERATE STUBS: {options.core_header} -> {options.build_dir}") +print(f"{sys.executable} {' '.join(sys.argv)}") + +os.makedirs(options.build_dir, exist_ok=True) +output_source = os.path.join(options.build_dir, 'stubs.cpp') + +with open(output_source, 'w') as stubs: + stubs.write(""" +// Copyright (c) 2015-2024 Vector 35 Inc +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Based on BinExport + +// Copyright 2011-2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define BINARYNINJACORE_LIBRARY +#include "binaryninjacore.h" +#undef BINARYNINJACORE_LIBRARY + +extern "C" { +""") + + with open(options.core_header, 'r') as header: + header_conts = header.read() + + # Quick preprocess of comments in case we have commented defs + header_conts = re.sub(r'//.*\n', '\n', header_conts) + + # Pull out all core api functions to generate stubs + for match in re.finditer( + r'(?m:)\t(BINARYNINJACOREAPI [^;]*);', + header_conts + ): + group = match.group(1) + + # Void functions don't have a return (TODO: breaks if we ever return a fn ptr) + void_group = re.search(r'(?m:)BINARYNINJACOREAPI\s+void\s+.*', group) + if void_group is not None: + stubs.write(f'{match.group(1)} {{ }}\n') + else: + stubs.write(f'{match.group(1)} {{ return {{ }}; }}\n') + + stubs.write(""" +} + """)
\ No newline at end of file |
