xll2cpp编译记录

VMware 安装 centOS 8

https://mirrors.aliyun.com/centos/8-stream/isos/x86_64/CentOS-Stream-8-x86_64-latest-dvd1.iso
https://blog.51cto.com/u_16596714/10118179
注意,swap分区不能像上述教程中设置2G,这样会出现后面build的时候的input/output错误,直接设置20G

安装nodejs 20

https://zhuanlan.zhihu.com/p/672114690

安装cmake

https://blog.csdn.net/muxuen/article/details/132591664

WMware设置共享文件夹并挂在puerts项目和ndk

https://blog.csdn.net/qq_34484062/article/details/116503084

[root@localhost hgfs]# cat /etc/fstab

#
# /etc/fstab
# Created by anaconda on Tue May  7 12:10:13 2024
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=f416eb3b-3309-42d2-a221-a99fb0d31e26 /                       xfs     defaults        0 0
UUID=1428cbef-4afa-4c9b-b345-2765e900223c /boot                   ext4    defaults        1 2
UUID=4e04735f-4409-4523-bee0-6978fc2af0e1 none                    swap    defaults        0 0
.host:/puerts /mnt/hgfs/puerts fuse.vmhgfs-fuse allow_other,defaults 0 0
.host:/ndk-linux /mnt/hgfs/ndk fuse.vmhgfs-fuse allow_other,defaults 0 0

添加ANDROID_NDK环境变量

vim ~/.bashrc添加环境变量,source ~/.bashrc使之生效

[root@localhost hgfs]# cat ~/.bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

export ANDROID_NDK=/mnt/hgfs/ndk/android-ndk-r21b

编译

说明
https://puerts.github.io/docs/puerts/unity/performance/il2cpp/

编译android+arm64

cd unity/native_src_il2cpp
node ../cli make --platform android --arch arm64

等待许久,报错了

[11%] Building CXX object CMakeFiles/puerts_il2cpp.dir/Src/Puerts.cpp.o

/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=aarch64-none-linux-android21 --gcc-toolchain=/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/sysroot -DEXPERIMENTAL_IL2CPP_PUERTS -DPLATFORM_ANDROID_ARM64 -DV8_94_OR_NEWER -I/mnt/hgfs/puerts/unity/native_src_il2cpp/Inc -I/mnt/hgfs/puerts/unity/native_src_il2cpp/../Assets/core/upm/Plugins/puerts_il2cpp -I/mnt/hgfs/puerts/unity/native_src_il2cpp/../native_src/.backends/v8_9.4/Inc -I/mnt/hgfs/puerts/unity/native_src_il2cpp/../native_src/Inc -I/mnt/hgfs/puerts/unity/native_src_il2cpp/../../unreal/Puerts/Source/JsEnv/Private -I/mnt/hgfs/puerts/unity/native_src_il2cpp/../../unreal/Puerts/ThirdParty/Include/websocketpp -I/mnt/hgfs/puerts/unity/native_src_il2cpp/../../unreal/Puerts/ThirdParty/Include/asio -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security   -O2 -DNDEBUG  -std=gnu++14 -fPIC -MD -MT CMakeFiles/puerts_il2cpp.dir/Src/Puerts.cpp.o -MF CMakeFiles/puerts_il2cpp.dir/Src/Puerts.cpp.o.d -o CMakeFiles/puerts_il2cpp.dir/Src/Puerts.cpp.o -c /mnt/hgfs/puerts/unity/native_src_il2cpp/Src/Puerts.cpp

/mnt/hgfs/puerts/unity/native_src_il2cpp/Src/Puerts.cpp:181:5: warning: ignoring return value of function declared with 'warn_unused_result' attribute [-Wunused-result]
    Obj->Set(Context, POEnv->SymbolCSPtr.Get(Isolate), v8::External::New(Context->GetIsolate(), runtimeObject));
    ^~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


clang++: error: unable to execute command: Killed
clang++: error: clang frontend command failed due to signal (use -v to see invocation)
Android (6317467 based on r365631c1) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project e0caee08e5f09b374a27a676d04978c81fcb1928) (based on LLVM 9.0.8svn)
Target: aarch64-none-linux-android21
Thread model: posix
InstalledDir: /mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin
clang++: note: diagnostic msg: PLEASE submit a bug report to https://github.com/android-ndk/ndk/issues and include the crash backtrace, preprocessed source, and associated run script.

百度了一下,是因为swap空间不足,故增加一个swap file
https://zhuanlan.zhihu.com/p/510257476
增加后:

[root@localhost ~]# swapon --show
NAME           TYPE      SIZE USED PRIO
/dev/nvme0n1p2 partition   2G   0B   -2
/swapfile      file       16G   0B   -3

再编译后成功生成:puerts/unity/Assets/core/upm/Plugins/Android/libs/arm64-v8a/libpuerts_il2cpp.a

编译android+armv7

root@localhost puerts]# ./build.sh
node --loader ts-node/esm /mnt/hgfs/puerts/unity/cli/cmd.mts make --platform android --arch armv7
(node:4243) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)

cmake --version

[Puer] download skip: v8_9.4 already exists 

cmake -DBACKEND_DEFINITIONS="V8_94_OR_NEWER" -DBACKEND_LIB_NAMES="/Lib/Android/armeabi-v7a/libwee8.a" -DBACKEND_INC_NAMES="/Inc" -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DJS_ENGINE=v8_9.4 -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI=armeabi-v7a -H. -B/mnt/hgfs/puerts/unity/native_src_il2cpp/build_android_armv7_v8_9.4 -DCMAKE_TOOLCHAIN_FILE=/mnt/hgfs/ndk/android-ndk-r21b/build/cmake/android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=android-21 -DANDROID_TOOLCHAIN=clang -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9

-- Detecting C compiler ABI info

-- Detecting C compiler ABI info - failed
-- Check for working C compiler: /mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang

-- Check for working C compiler: /mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang - broken

CMake Error at /usr/local/share/cmake-3.29/Modules/CMakeTestCCompiler.cmake:67 (message):
  The C compiler

    "/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: '/mnt/hgfs/puerts/unity/native_src_il2cpp/build_android_armv7_v8_9.4/CMakeFiles/CMakeScratch/TryCompile-GvSIHC'
    
    Run Build Command(s): /usr/local/bin/cmake -E env VERBOSE=1 /usr/bin/gmake -f Makefile cmTC_15833/fast
    /usr/bin/gmake  -f CMakeFiles/cmTC_15833.dir/build.make CMakeFiles/cmTC_15833.dir/build
    gmake[1]: Entering directory '/mnt/hgfs/puerts/unity/native_src_il2cpp/build_android_armv7_v8_9.4/CMakeFiles/CMakeScratch/TryCompile-GvSIHC'
    Building C object CMakeFiles/cmTC_15833.dir/testCCompiler.c.o
    /mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=armv7-none-linux-androideabi21 --gcc-toolchain=/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/sysroot   -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security   -fPIE -MD -MT CMakeFiles/cmTC_15833.dir/testCCompiler.c.o -MF CMakeFiles/cmTC_15833.dir/testCCompiler.c.o.d -o CMakeFiles/cmTC_15833.dir/testCCompiler.c.o -c /mnt/hgfs/puerts/unity/native_src_il2cpp/build_android_armv7_v8_9.4/CMakeFiles/CMakeScratch/TryCompile-GvSIHC/testCCompiler.c
    Linking C executable cmTC_15833
    /usr/local/bin/cmake -E cmake_link_script CMakeFiles/cmTC_15833.dir/link.txt --verbose=1
    /mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=armv7-none-linux-androideabi21 --gcc-toolchain=/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security   -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -Wl,--gc-sections   CMakeFiles/cmTC_15833.dir/testCCompiler.c.o -o cmTC_15833  -latomic -lm
    /mnt/hgfs/ndk/android-ndk-r21b/toolchains/llvm/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: fatal error: cmTC_15833: Input/output error
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    gmake[1]: *** [CMakeFiles/cmTC_15833.dir/build.make:100: cmTC_15833] Error 1
    gmake[1]: Leaving directory '/mnt/hgfs/puerts/unity/native_src_il2cpp/build_android_armv7_v8_9.4/CMakeFiles/CMakeScratch/TryCompile-GvSIHC'
    gmake: *** [Makefile:127: cmTC_15833/fast] Error 2
    
    

  

  CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
  CMakeLists.txt:10 (project)



-- Configuring incomplete, errors occurred!

node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

AssertionError [ERR_ASSERTION]: 0 == 1
    at Object.hook (file:///mnt/hgfs/puerts/unity/cli/make.mts:19:24)
    at runPuertsMake (file:///mnt/hgfs/puerts/unity/cli/make.mts:201:34) {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: 0,
  expected: 1,
  operator: '=='
}

Node.js v20.12.2

又出现input/output的问题,这次应该和swap分区没关系了,看到下面这篇文章
http://t.csdnimg.cn/QArGJ
受其启发,我确实是把puerts工程通过共享文件夹并挂载到mnt后进行编译的,会不会与此有关?于是把工程copy到usr/works里再试试,果然编译成功:

[root@localhost armeabi-v7a]# ls -l /usr/works/unity/Assets/core/upm/Plugins/Android/libs/armeabi-v7a/libpuerts_il2cpp.a
-rw-r--r--. 1 root root 146860860 May  8 19:13 /usr/works/unity/Assets/core/upm/Plugins/Android/libs/armeabi-v7a/libpuerts_il2cpp.a

xll2cpp不能用于webgl

Assets\Puerts_webgl\Runtime\WebGL.cs, line 66

[MonoPInvokeCallback(typeof(CallV8Function))]
internal static void CallV8FunctionCallback(int functionCallback, int info, int self, int paramLen, int callbackIdx)
{
      V8FunctionCallback callback =
      Marshal.GetDelegateForFunctionPointer<V8FunctionCallback>(new IntPtr(functionCallback));
      callback.Invoke(IntPtr.Zero, new IntPtr(info), new IntPtr(self), paramLen, Utils.TwoIntToLong(0, callbackIdx));
}

MonoPInvokeCallback定义于puerts/unity/Assets/core/upm/Runtime/Src/Default/Native/PuertsDLL.cs

#if !EXPERIMENTAL_IL2CPP_PUERTS || !ENABLE_IL2CPP

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Puerts
{
#pragma warning disable 414
    public class MonoPInvokeCallbackAttribute : System.Attribute
    {
        // ...
    }
    // ...
}
#endif

关于ENABLE_IL2CPP

本地编辑器跑项目时,尽管BuildSetting里添加了define symbolsPUERTS_CPP_OUTPUT_TO_NATIVE_SRC_UPM;EXPERIMENTAL_IL2CPP_PUERTS,也开启了il2cpp,但是JsEnv一直跑的是unity\Assets\core\upm\Runtime\Src\Default\JsEnv.cs而非unity\Assets\core\upm\Runtime\Src\IL2Cpp\JsEnv.cs。原因在于unity编辑器模式下不支持il2cpp,解释见:
https://github.com/Tencent/puerts/issues/1380

关于libpuerts_il2cpp.a

Plugin 'Packages/com.tencent.puerts.core/Plugins/Android/libs/armeabi-v7a/libpuerts_il2cpp.a' doesn't have CPU architecture set, since it's a native plugin, valid architecture is required, skipping.
image.png

检查了相关插件的Import Settings是正确的,但就是一直提示这个错误。最后尝试将CPU先改为arm64再改回armv7,竟然就好了!

Could not determine the dependencies of task xxx

Could not determine the dependencies of task ':bugly:compileReleaseAidl'.
Installed Build Tools revision 34.0.0 is corrupted. Remove and install again using the SDK Manager.

我用的unity版本是2021.2.18f1,估计默认是34.0.0,和bugly的冲突了,把所有*.gradle *.properties中的buildToolsVersion改成一样的就行了。这里修改了${安卓工程}/launcher/build.gradle${安卓工程}/launcher/gradle.properties,统一改为30.0.2

关于unityenv_for_puerts.h

项目进行安卓打包时报错:

Error: Unity.IL2CPP.Building.BuilderFailedException: Build failed with 453 successful nodes and 2 failed ones
Annotation: C_Android_arm32 iz17/rnjx_rts_il2cpp.o
Cmdline: "D:/android-ndk-windows/r21d/toolchains/llvm/prebuilt/windows-x86_64/bin/clang++" -march=armv7-a -mfloat-abi=                                                                                                                       softfp -mfpu=neon-fp16 -marm -D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -D__ANDROID_API__=22 -DANDROID -DHAVE_INTTYPES_H -no-c                                                                                                                       anonical-prefixes -funwind-tables -fstack-protector -fdiagnostics-format=msvc -fomit-frame-pointer -std=c++11 -Wswitch                                                                                                                        -Wno-trigraphs -Wno-tautological-compare -Wno-invalid-offsetof -Wno-implicitly-unsigned-literal -Wno-integer-overflow                                                                                                                        -Wno-shift-negative-value -Wno-unknown-attributes -Wno-implicit-function-declaration -Wno-null-conversion -Wno-missin                                                                                                                       g-declarations -Wno-unused-value -Wno-pragma-once-outside-header -fvisibility=hidden -fexceptions -fno-rtti -g -O2 -fP                                                                                                                       IC -fno-strict-overflow -ffunction-sections -fdata-sections -fmessage-length=0 -pipe -DBASELIB_INLINE_NAMESPACE=il2cpp                                                                                                                       _baselib -DIL2CPP_MONO_DEBUGGER_DISABLED -DRUNTIME_IL2CPP -DIL2CPP_ENABLE_WRITE_BARRIERS=1 -DIL2CPP_INCREMENTAL_TIME_S                                                                                                                       LICE=3 -DHAVE_BDWGC_GC -DNDEBUG -I"." -I"F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppO                                                                                                                       utputProject/Source/il2cppOutput" -I"F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutpu                                                                                                                       tProject/IL2CPP/libil2cpp/pch" -I"F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputPr                                                                                                                       oject/IL2CPP/libil2cpp" -I"F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/I                                                                                                                       L2CPP/external/baselib/Include" -I"F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputP                                                                                                                       roject/IL2CPP/external/baselib/Platforms/Android/Include" -o "iz17/rnjx_rts_il2cpp.o" -fcolor-diagnostics -fdiagnostic                                                                                                                       s-absolute-paths -target armv7a-linux-androideabi22 -fstrict-aliasing -fdiagnostics-format=msvc -c -x c++ "F:/games/Do                                                                                                                       uPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp"
ExitCode: 1
Stdout:
F:\games\DouPoAndroid_CN_Develop_xll2cpp\export\unityLibrary\src\main\Il2CppOutputProject\Source\il2cppOutput\Puerts_i                                                                                                                       l2cpp.cpp(9,10): fatal error: 'unityenv_for_puerts.h' file not found
#include "unityenv_for_puerts.h"
         ^~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

puerts\unity\Assets\core\upm\Plugins\puerts_il2cpp下的unityenv_for_puerts.h复制到${安卓工程}\unityLibrary\src\main\Il2CppOutputProject\Source\il2cppOutput下即可。同理,把pesapi.hUnityExports4Puerts.h也一起复制过去。

Puerts_il2cpp.cpp报错

F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp:476: error: undefined reference to 'pesapi_create_string_utf8'
F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp:487: error: undefined reference to 'pesapi_create_boolean'
F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp:0: error: undefined reference to 'pesapi_create_int32'
F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp:0: error: undefined reference to 'pesapi_create_uint32'
F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp:524: error: undefined reference to 'pesapi_create_int64'
F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp:531: error: undefined reference to 'pesapi_create_uint64'
F:/games/DouPoAndroid_CN_Develop_xll2cpp/export/unityLibrary/src/main/Il2CppOutputProject/Source/il2cppOutput/Puerts_il2cpp.cpp:0: error: undefined reference to 'pesapi_create_double

某些CS类的静态变量是undefined

企业微信截图_17170665815269.png

如上图,BuildDefines.definesundefined
经过测试,如果在CS中显式地用到了BuildDefines.defines,不会出现上述报错。看起来似乎是il2cpp stripe code导致的。但是在CS中通过反射可以取到fielddefines
csharp.mjs中增加日志
image.png

编辑器中可以打印出相关日志,但模拟器中并不会打印出来
企业微信截图_17171245113535.png

说明il2cpp不会走readonlyStaticMembers这个逻辑。看了源码确实如此,readonlyStaticMembers是在JSEngine::RegisterProperty中处理的,而只有unity\Assets\core\upm\Runtime\Src\Default\Native\PuertsDLL.cs调用了该接口,而这个文件是非xll2cpp模式下才使用的,xll2cpp模式下跑的是unity\Assets\core\upm\Runtime\Src\IL2Cpp\Native\NativeAPI.cs
再看看相关流程:

public JsEnv(ILoader loader, int debugPort = -1)
{
    ...
    tryLoadTypeMethodInfo = typeof(TypeRegister).GetMethod("RegisterNoThrow");
    PuertsIl2cpp.NativeAPI.SetTryLoadCallback(PuertsIl2cpp.NativeAPI.GetMethodInfoPointer(tryLoadTypeMethodInfo), PuertsIl2cpp.NativeAPI.GetMethodPointer(tryLoadTypeMethodInfo));
    ...
    const string AutoStaticCodeRegisterClassName = "PuertsStaticWrap.PuerRegisterInfo_Gen";
    var autoRegister = Type.GetType(AutoStaticCodeRegisterClassName, false);
    ...
    var methodInfoOfRegister = autoRegister.GetMethod("AddRegisterInfoGetterIntoJsEnv");
    ...
    methodInfoOfRegister.Invoke(null, new object[] { this });
    ...
}
    

tryLoadTypeMethodInfo最终赋予JSClassRegister::LazyLoad

// unity\native_src_il2cpp\Src\PesapiV8Impl.cpp
void pesapi_define_class(const void* type_id, const void* super_type_id, const char* type_name, pesapi_constructor constructor,
    pesapi_finalize finalize, size_t property_count, pesapi_property_descriptor properties, void* userdata)
{
    // ...
    puerts::RegisterJSClass(classDef);
}
// unity\native_src_il2cpp\Src\JSClassRegister.cpp
void RegisterJSClass(const JSClassDefinition& ClassDefinition)
{
    GetJSClassRegister()->RegisterClass(ClassDefinition);
}
void JSClassRegister::RegisterClass(const JSClassDefinition& ClassDefinition)
{
    // ...
}

pesapi_define_class又是如何调用的?

// unity\native_src_il2cpp\Src\PesapiAddonLoad.cpp
V8_EXPORT pesapi_func_ptr* GetPesapiImpl()
{
    return funcs;
}
// unity\Assets\core\upm\Runtime\Src\IL2Cpp\JsEnv.cs
public JsEnv(ILoader loader, int debugPort = -1)
{
    // ...
    PuertsIl2cpp.NativeAPI.InitialPuerts(PuertsIl2cpp.NativeAPI.GetPesapiImpl());
    // ...
}
// unity\Assets\core\upm\Plugins\puerts_il2cpp\Puerts_il2cpp.cpp
void InitialPuerts(pesapi_func_ptr* func_array)
{
    // ...
    pesapi_init(func_array);
}
// unity\Assets\core\upm\Plugins\puerts_il2cpp\pesapi_adpt.c
void pesapi_init(pesapi_func_ptr* func_array){
    // ...
}
// unity\native_src_il2cpp\Inc\Binding.hpp
void Register(FinalizeFuncType Finalize)
{
    // ...
    pesapi_define_class(StaticTypeId<T>::get(), superTypeId_, className_, constructor_, finalize, properties_count, properties);
}

最后看下BuildDefines的整个流程:

// unity\Assets\core\upm\Runtime\Src\IL2Cpp\JsEnv.cs
var methodInfoOfRegister = autoRegister.GetMethod("AddRegisterInfoGetterIntoJsEnv");
methodInfoOfRegister.Invoke(null, new object[] { this });
// Assets\Gen\RegisterInfo_Gen.cs
jsEnv.AddRegisterInfoGetter(typeof(BuildDefines), GetRegisterInfo_BuildDefines_Wrap);
...
// unity\Assets\core\upm\Runtime\Src\IL2Cpp\JsEnv.cs
TypeRegister.AddRegisterInfoGetter(type, getter);
// unity\Assets\core\upm\Runtime\Src\IL2Cpp\TypeRegister.cs
RegisterInfoManager.Add(type, getter);
// unity\Assets\core\upm\Runtime\Src\RegisterInfoManager.cs
RegisterInfoGetters.Add(type, RegisterInfoGetter);

// ...

// 下面看看BuildDefines::defines
// unity\Assets\core\upm\Runtime\Src\IL2Cpp\TypeRegister.cs
var wrapper = GetFieldWrapper(registerInfo, name, field.IsStatic, signature);
...
NativeAPI.AddField(
    typeInfo,
    wrapper,
    ...
)
// GetFieldWrapper又是怎样的
if (bindingMode == BindingMode.FastBinding)
{
    wrapper = NativeAPI.FindFieldWrap(signature);
}

// 下面看看js访问defines时发生了什么
// TsScripts\System\data\SysDefines.ts
let buildds = CS.BuildDefines.defines.split('.');
// unity\Assets\core\upm\Runtime\Resources\puerts\csharp.mjs
let cls = puer.loadType(csType);
// unity\native_src_il2cpp\Src\Puerts.cpp
auto Ret = pom->LoadTypeById(Isolate, Context, type);
// unity\native_src_il2cpp\Src\CppObjectMapper.cpp
auto Template = GetTemplateOfClass(Isolate, TypeId);
...
PropertyInfo = ClassDefinition->Variables;
...
Template->SetAccessorProperty(
    v8::String::NewFromUtf8(Isolate, PropertyInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
    v8::FunctionTemplate::New(Isolate, PropertyInfo->Getter, GetterData),
    v8::FunctionTemplate::New(Isolate, PropertyInfo->Setter, SetterData), PropertyAttribute);
...
// unity\native_src_il2cpp\Src\FunctionBridge.Gen.h
static void ifg_s(const v8::FunctionCallbackInfo<v8::Value>& info, void* fieldInfo, size_t offset, void* TIret) {
    PLog(LogLevel::Log, "Running ifg_s");

    v8::Isolate* isolate = info.GetIsolate();
    v8::Local<v8::Context> context = isolate->GetCurrentContext();
    void* ret;

    FieldGet(nullptr, fieldInfo, offset, &ret);
    
    info.GetReturnValue().Set(CSAnyToJsValue(isolate, context, ret));
}
// unity\native_src_il2cpp\Src\Puerts.cpp
inline static v8::Local<v8::Value> CSAnyToJsValue(v8::Isolate* Isolate, v8::Local<v8::Context> Context, void* Obj)
{
    ...
    pesapi_value jsVal = GUnityExports.TryTranslatePrimitive(*Context, Obj);
    ...
}
// unity\Assets\core\upm\Plugins\puerts_il2cpp\Puerts_il2cpp.cpp
pesapi_value TryTranslatePrimitive(pesapi_env env, Il2CppObject* obj)
{
    return TryTranslatePrimitiveWithClass(env, obj);
}
...
static pesapi_value TryTranslatePrimitiveWithClass(pesapi_env env, Il2CppObject* obj, Il2CppClass *klass = nullptr)
{
    if (obj)
    {
        const Il2CppType *type = Class::GetType(klass ? klass : obj->klass);
        int t = type->type;
        if (t == IL2CPP_TYPE_STRING)
        {
            const Il2CppChar* utf16 = il2cpp::utils::StringUtils::GetChars((Il2CppString*)obj);
            std::string str = il2cpp::utils::StringUtils::Utf16ToUtf8(utf16);
            return pesapi_create_string_utf8(env, str.c_str(), str.size());
        }
    ...
    }
}

最终通过打日志发现是在unity\Assets\core\upm\Plugins\puerts_il2cpp\Puerts_il2cpp.cpp中,Field::SetValueRaw没有取得对应的值。

企业微信截图_17173954939055.png

image.png

企业微信截图_17173980252683.png

这说明,即便xll2cpp模式生成了linker.xml,通过反射也可以取得defines的值,但直接通过CS.BuildDefine.defines却无法取得正确的值。

void GetFieldValue(void *ptr, FieldInfo *field, size_t offset, void *value)
{
    void *src;

    if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
    {
        IL2CPP_ASSERT(ptr);
        src = (char*)ptr + offset;
        Field::SetValueRaw(field->type, value, src, true);
    }
    else
    {
        Field::StaticGetValue(field, value);
    }
}

更神奇的是跟踪了半天后,后来不知道咋的这个问题消失了...

ArrayBuffer优化

unity\Assets\core\upm\Runtime\Src\ArrayBuffer.cs
unity\Assets\core\upm\Runtime\Src\Default\Translator\NativeValueApiGeneric.cs
目前js和cs交互时,new ArrayBuffer总是会创建新数组:

public ArrayBuffer(IntPtr ptr, int length)
{
    if (ptr != IntPtr.Zero)
    {
        Bytes = new byte[length];
        Count = length;
        System.Runtime.InteropServices.Marshal.Copy(ptr, Bytes, 0, length);
    }
}

修改成直接使用指针

public ArrayBuffer(IntPtr ptr, int length)
{
    if (ptr != IntPtr.Zero)
    {
        BytesPtr = ptr;
        Count = length;
    }
}

xll2cpp相关

jsEnv

unity\native_src_il2cpp\Src\Puerts.cpp定义了SetObjectToGlobal

V8_EXPORT void SetObjectToGlobal(puerts::JSEnv* jsEnv, const char* key, void *obj)
{
    if (obj)
    {
        v8::Isolate* Isolate = jsEnv->MainIsolate;
        v8::Isolate::Scope IsolateScope(Isolate);
        v8::HandleScope HandleScope(Isolate);
        v8::Local<v8::Context> Context = jsEnv->MainContext.Get(Isolate);
        v8::Context::Scope ContextScope(Context);
        
        void* klass = *reinterpret_cast<void**>(obj);
        Context->Global()->Set(Context, v8::String::NewFromUtf8(Isolate, key).ToLocalChecked(), puerts::DataTransfer::FindOrAddCData(Isolate, Context, klass, obj, true)).Check();
    }
}

unity\Assets\core\upm\Runtime\Src\IL2Cpp\JsEnv.cs注册了全局的js变量jsEnv:

PuertsIl2cpp.NativeAPI.SetObjectToGlobal(nativeJsEnv, "jsEnv", PuertsIl2cpp.NativeAPI.GetObjectPointer(this));

这样,在unity\Assets\core\upm\Runtime\Resources\puerts\init_il2cpp.mjs中通过jsEnv获取CS类:

puer.loadType = function(nameOrCSType, ...genericArgs) {
    let csType = nameOrCSType
    if (typeof nameOrCSType == "string") { // convert string to csType
        csType = jsEnv.GetTypeByString(nameOrCSType)
    }
    if (csType) {
        if (genericArgs && csType.IsGenericTypeDefinition) {
            genericArgs = genericArgs.map(g => puer.$typeof(g));
            csType = csType.MakeGenericType(...genericArgs);
        }
        let cls = loadType(csType)
        cls.__p_innerType = csType
        // todo
        cls.__puertsMetadata = cls.__puertsMetadata || new Map();
        return cls
    }
}

unity\Assets\core\upm\Plugins\puerts_il2cpp\Puerts_il2cpp.cpp中定义了g_unityExports,这个文件涉及unity il2cpp相关。

静态常量

unity\native_src\Src\JSEngine.cpp中,JSEngine::RegisterProperty设置了readonlyStaticMembers:

if (!NotReadonlyStatic) 
{
    v8::Local<v8::Map> Metadata = Metadatas[ClassID].Get(Isolate);
    v8::Local<v8::Set> ReadonlyStaticMembersSet;
    v8::Local<v8::Value> NameOfTheSet = FV8Utils::V8String(Isolate, "readonlyStaticMembers");
    v8::Local<v8::Value> ReadonlyStaticMembersSetValue = Metadata->Get(Context, NameOfTheSet).ToLocalChecked();
    if (ReadonlyStaticMembersSetValue->IsNullOrUndefined())
    {
        ReadonlyStaticMembersSet = v8::Set::New(Isolate);
        Metadata->Set(Context, NameOfTheSet, ReadonlyStaticMembersSet);
    }
    else
    {
        ReadonlyStaticMembersSet = v8::Local<v8::Set>::Cast(ReadonlyStaticMembersSetValue);
    }
    ReadonlyStaticMembersSet->Add(Context, FV8Utils::V8String(Isolate, Name));
}

接下来在unity\Assets\core\upm\Runtime\Resources\puerts\csharp.mjs的``csTypeToClass中:

if (readonlyStaticMembers = cls.__puertsMetadata.get('readonlyStaticMembers')) {
    // ...
}

默认BindingMode

JsEnv::SetDefaultBindingMode
unity\Assets\core\upm\Runtime\Src\Default\JsEnv.cs

ios xcode打包报错:'../../external/google/sparsehash/sparse_hash_map.h' file not found

之前一直用的2019版本,这次升级到2022.3.14f1后,打ios时报错

企业微信截图_17176596088293.png

对比2019和2022的产出,发现两者并无区别:
企业微信截图_17176710384204.png

企业微信截图_17176710578698.png

那问题就应该出在unity身上,对比两个版本的Unity安装目录\Editor\Data\il2cpp\libil2cpp\il2cpp-config.h发现:
企业微信截图_17176711017178.png

也就是2022默认在打安卓和ios时启用了IL2CPP_USE_SPARSEHASH,解决方法就是把

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 175,490评论 5 419
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 74,060评论 2 335
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 124,407评论 0 291
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 47,741评论 0 248
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 56,543评论 3 329
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 43,040评论 1 246
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 34,107评论 3 358
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 32,646评论 0 229
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 36,694评论 1 271
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 32,398评论 2 279
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 33,987评论 1 288
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 30,097评论 3 285
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 35,298评论 3 282
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 27,278评论 0 14
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 28,413评论 1 232
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 38,397评论 2 309
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 38,099评论 2 314

推荐阅读更多精彩内容