diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb453739..ee5c327b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: JNI Bind Build/Test Status on: push: - branches: [ "main" ] + branches: '*' pull_request: - branches: [ "main" ] + branches: '*' permissions: contents: read @@ -46,3 +46,13 @@ jobs: - uses: actions/checkout@v4 - name: test run: bazel test --cxxopt='-Werror' --cxxopt='-std=c++20' --repo_env=CC=clang --test_output=errors ... + + windows-2019-cpp20-cmake-mvsc: + runs-on: windows-2019 + steps: + - name: checkout + uses: actions/checkout@v4 + - name: cmake configure + run: cmake --preset msvc-16-config-debug + - name: cmake build + run: cmake --build --preset msvc-16-build-debug diff --git a/.gitignore b/.gitignore index c8db4504..cf703b06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bazel* .vscode MODULE.bazel.lock -cmake-build +cmake_build +cmake_install \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..05062e2c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.20.0) + +file(READ ${CMAKE_SOURCE_DIR}/JNI_BIND_VERSION.inc JNI_BIND_VERSION) +project(jni-bind VERSION "${JNI_BIND_VERSION}" LANGUAGES C CXX) + +include(${CMAKE_SOURCE_DIR}/cmake/add_jni_test.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/compile_flags.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/find_dependencies.cmake) + +# main target +add_library(jni_bind INTERFACE) + +target_include_directories(jni_bind INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/class_defs + ${CMAKE_CURRENT_SOURCE_DIR}/implementation + ${CMAKE_CURRENT_SOURCE_DIR}/implementation/jni_helper + ${CMAKE_CURRENT_SOURCE_DIR}/metaprogramming) + +target_link_libraries(jni_bind INTERFACE jdk:jni) + +# Testsuite +if (NOT TARGET gtest_main) + return() +endif() + +enable_testing() + +file(GLOB METAPROGRAMMING_TESTS "${CMAKE_SOURCE_DIR}/metaprogramming/*_test.cc") +foreach(TEST_SRC ${METAPROGRAMMING_TESTS}) + get_filename_component(TEST_NAME ${TEST_SRC} NAME_WE) + add_jni_test(${TEST_NAME} ${TEST_SRC}) +endforeach() + +file(GLOB IMPLEMENTATION_TESTS "${CMAKE_SOURCE_DIR}/implementation/*_test.cc") +foreach(TEST_SRC ${IMPLEMENTATION_TESTS}) + get_filename_component(TEST_NAME ${TEST_SRC} NAME_WE) + add_jni_test(${TEST_NAME} ${TEST_SRC}) +endforeach() + +file(GLOB JNI_HELPER_TESTS "${CMAKE_SOURCE_DIR}/implementation/jni_helper/*_test.cc") +foreach(TEST_SRC ${JNI_HELPER_TESTS}) + get_filename_component(TEST_NAME ${TEST_SRC} NAME_WE) + add_jni_test(${TEST_NAME} ${TEST_SRC}) +endforeach() \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000..cea49c13 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,70 @@ +{ + "version": 6, + + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + + "configurePresets": [ + { + "hidden": true, + "name": "msvc-16-base", + "generator": "Visual Studio 16 2019", + "binaryDir": "${sourceDir}/cmake_build", + "architecture": { + "value": "x64", + "strategy": "external" + } + }, + { + "name": "msvc-16-config-debug", + "inherits": "msvc-16-base", + "installDir": "${sourceDir}/cmake_install/Debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "msvc-16-config-release", + "inherits": "msvc-16-base", + "installDir": "${sourceDir}/cmake_install/Release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + } + ], + + "buildPresets": [ + { + "name": "msvc-16-build-debug", + "configurePreset": "msvc-16-config-debug", + "configuration": "Debug", + "jobs": 4 + }, + { + "name": "msvc-16-build-release", + "configurePreset": "msvc-16-config-release", + "configuration": "Release", + "jobs": 4 + } + ], + + "testPresets": [ + { + "name": "msvc-16-test-debug", + "configurePreset": "msvc-16-config-debug", + "configuration": "Debug", + "output": { + "outputOnFailure": true, + "verbosity": "verbose" + }, + "execution": { + "noTestsAction": "error", + "stopOnFailure": true + } + } + ] + +} \ No newline at end of file diff --git a/JNI_BIND_VERSION.inc b/JNI_BIND_VERSION.inc index 26aaba0e..867e5243 100644 --- a/JNI_BIND_VERSION.inc +++ b/JNI_BIND_VERSION.inc @@ -1 +1 @@ -1.2.0 +1.2.0 \ No newline at end of file diff --git a/cmake/add_jni_test.cmake b/cmake/add_jni_test.cmake new file mode 100644 index 00000000..b2e5a612 --- /dev/null +++ b/cmake/add_jni_test.cmake @@ -0,0 +1,19 @@ +function(add_jni_test test_name test_source) + + # workaround duplicated target test name "invoke_test" + if (TARGET ${test_name}) + set(test_name ${test_name}_2) + endif() + + add_executable(${test_name} ${test_source}) + + target_link_libraries(${test_name} + PRIVATE + jni_bind + gmock + gtest_main) + + add_test( + NAME ${test_name} + COMMAND ${test_name}) +endfunction() \ No newline at end of file diff --git a/cmake/compile_flags.cmake b/cmake/compile_flags.cmake new file mode 100644 index 00000000..b9108899 --- /dev/null +++ b/cmake/compile_flags.cmake @@ -0,0 +1,14 @@ +message("Detected compiler [${CMAKE_CXX_COMPILER_ID}]") + +SET(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(MSVC) + set(CXX_FLAGS "/Zc:__cplusplus /EHsc") +#elseif(Clang) +# ... +endif() + +set(CMAKE_CXX_FLAGS "${CXX_FLAGS}" CACHE STRING "" FORCE) +#set(CMAKE_CXX_FLAGS_DEBUG "" CACHE STRING "" FORCE) +#set(CMAKE_CXX_FLAGS_RELEASE "" CACHE STRING "" FORCE) \ No newline at end of file diff --git a/cmake/find_dependencies.cmake b/cmake/find_dependencies.cmake new file mode 100644 index 00000000..43016c52 --- /dev/null +++ b/cmake/find_dependencies.cmake @@ -0,0 +1,22 @@ +# JNI +find_package(JNI REQUIRED) +if (NOT JNI_FOUND) + message(FATAL_ERROR "JDK/JNI environment not found") +endif() + +if (NOT TARGET jdk:jni) + add_library(jdk:jni INTERFACE IMPORTED GLOBAL) + + set_target_properties( + jdk:jni + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${JNI_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${JNI_LIBRARIES}") +endif() + +# GoogleTest +include(FetchContent) +FetchContent_Declare(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG f8d7d77) # 1.14.0 +FetchContent_MakeAvailable(googletest) \ No newline at end of file diff --git a/implementation/class.h b/implementation/class.h index 18a52196..cd6b3b94 100644 --- a/implementation/class.h +++ b/implementation/class.h @@ -172,13 +172,12 @@ struct Class, //////////////////////////////////////////////////////////////////////////////// // Equality operators. //////////////////////////////////////////////////////////////////////////////// -template +template < + typename LhsParentClass, typename... LhsParams, typename... LhsConstructors, + typename... LhsStaticMethods, typename... LhsStaticFields, + typename... LhsFields, typename... LhsMethods, typename RhsParentClass, + typename... RhsConstructors, typename... RhsStaticMethods, + typename... RhsStaticFields, typename... RhsFields, typename... RhsMethods> constexpr bool operator==( const Class, std::tuple, diff --git a/implementation/jni_helper/jni_array_helper.h b/implementation/jni_helper/jni_array_helper.h index 46ab9396..56ea44b7 100644 --- a/implementation/jni_helper/jni_array_helper.h +++ b/implementation/jni_helper/jni_array_helper.h @@ -290,7 +290,7 @@ struct JniArrayHelper : public JniArrayHelperBase { #endif // DRY_RUN } - static inline void ReleaseArrayElements(jarray array, int* native_ptr, + static inline void ReleaseArrayElements(jarray array, jint* native_ptr, bool copy_on_completion) { Trace( metaprogramming::LambdaToStr(STR("ReleaseArrayElements, jint, Rank 1")), diff --git a/implementation/no_class_specified.h b/implementation/no_class_specified.h index ae90446f..ab55f966 100644 --- a/implementation/no_class_specified.h +++ b/implementation/no_class_specified.h @@ -25,16 +25,18 @@ namespace jni { -struct ExtendsBase {}; +struct ExtendsBase { + constexpr ExtendsBase() {} +}; struct RootObject { - constexpr RootObject() = default; + constexpr RootObject() {} }; -static constexpr RootObject kObject{}; +constexpr RootObject kObject{}; -static constexpr struct NoClass { - // For compatability reasons, this must be defined (not default) because some +constexpr struct NoClass { + // For compatibility reasons, this must be defined (not default) because some // compilers will complain about defaulted constructors being deleted. constexpr NoClass() {} diff --git a/implementation/proxy_definitions.h b/implementation/proxy_definitions.h index 9a5b0a1a..09058b9c 100644 --- a/implementation/proxy_definitions.h +++ b/implementation/proxy_definitions.h @@ -82,6 +82,27 @@ struct Proxy::template value; }; +// jint is differently sized on Windows platforms. This surely leads to widening +// issues for lay developers, but we will try to silently widen for them. +template +struct Proxy && + !std::is_same_v>> + : public ProxyBase { + using AsArg = std::tuple; + using AsDecl = std::tuple; + + template + static constexpr bool kViable = IsConvertibleKey::template value || + IsConvertibleKey::template value; + + static jint ProxyAsArg(jint val) { return val; } + + template >> + static jint ProxyAsArg(T val) { + return static_cast(val); + } +}; + template struct Proxy>> diff --git a/metaprogramming/BUILD b/metaprogramming/BUILD index 7653892a..4b5b2715 100644 --- a/metaprogramming/BUILD +++ b/metaprogramming/BUILD @@ -1207,26 +1207,6 @@ cc_library( hdrs = ["vals.h"], ) -cc_library( - name = "vals_equal", - hdrs = ["vals_equal.h"], - - # This is incompatibel with MSVC, do not use. - visibility = ["//visibility:private"], - deps = [":vals"], -) - -cc_test( - name = "vals_equal_test", - srcs = ["vals_equal_test.cc"], - tags = ["manual"], - deps = [ - ":vals", - ":vals_equal", - "@googletest//:gtest_main", - ], -) - cc_library( name = "vals_equal_diminished", hdrs = ["vals_equal_diminished.h"], diff --git a/metaprogramming/vals_equal.h b/metaprogramming/vals_equal.h deleted file mode 100644 index 0b7865e4..00000000 --- a/metaprogramming/vals_equal.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2022 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef JNI_BIND_METAPROGRAMMING_VALS_EQUAL_H_ -#define JNI_BIND_METAPROGRAMMING_VALS_EQUAL_H_ - -#include - -#include "metaprogramming/vals.h" - -namespace jni::metaprogramming { - -// Performs a deep equality comparison of T, but is leniant about containers. -// Returns true iff types are equal or both types are containers and their -// non-type template parameters are equal. -template -struct ValsEqual { - template - struct Helper { - static constexpr bool val = std::is_same_v; - }; - - // Value comparison. - template