VS2017链接V8引擎库遇到的一些问题

前几天用VS2017编译好了V8库,今天尝试编译Demo程序的时候遇到了一些问题:
V8的坑真的不是一般的多

#include "AppConfig.h"

#include "libplatform/libplatform.h"
#include "v8.h"

AppConfig* AppConfig::_ins = nullptr;

bool AppConfig::loadFile(std::string fileName)
{
	lua_State* L;
	L = luaL_newstate();
	v8::V8::InitializeICUDefaultLocation(".");
	v8::V8::InitializeExternalStartupData(".");
	
	std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
	v8::V8::InitializePlatform(platform.get());
	v8::V8::Initialize();
	v8::Isolate::CreateParams create_params;
	create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
	v8::Isolate* isolate = v8::Isolate::New(create_params);
	{
		v8::Isolate::Scope isolate_scope(isolate);
		// Create a stack-allocated handle scope.
		v8::HandleScope handle_scope(isolate);
		// Create a new context.
		v8::Local<v8::Context> context = v8::Context::New(isolate);
		// Enter the context for compiling and running the hello world script.
		v8::Context::Scope context_scope(context);
		// Create a string containing the JavaScript source code.
		v8::Local<v8::String> source =
			v8::String::NewFromUtf8(isolate, "'Hello' + ', World!'",
				v8::NewStringType::kNormal)
			.ToLocalChecked();
		// Compile the source code.
		v8::Local<v8::Script> script =
			v8::Script::Compile(context, source).ToLocalChecked();
		// Run the script to get the result.
		v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
		// Convert the result to an UTF8 string and print it.
		v8::String::Utf8Value utf8(isolate, result);
		printf("%s\n", *utf8);
	}
	// Dispose the isolate and tear down V8.
	isolate->Dispose();
	v8::V8::Dispose();
	v8::V8::ShutdownPlatform();
	delete create_params.array_buffer_allocator;

	return false;
}

AppConfig::AppConfig()
{
}


AppConfig::~AppConfig()
{
}
1>AppConfig.obj : error LNK2019: 无法解析的外部符号 "class std::unique_ptr<class v8::Platform,struct std::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::unique_ptr<class v8::TracingController,struct std::default_delete<class v8::TracingController> >)" (?NewDefaultPlatform@platform@v8@@YA?AV?$unique_ptr@VPlatform@v8@@U?$default_delete@VPlatform@v8@@@std@@@std@@HW4IdleTaskSupport@12@W4InProcessStackDumping@12@V?$unique_ptr@VTracingController@v8@@U?$default_delete@VTracingController@v8@@@std@@@4@@Z),该符号在函数 "public: bool __cdecl AppConfig::loadFile(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?loadFile@AppConfig@@QEAA_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) 中被引用
1>D:\projects\aps2\x64\Debug\aps.exe : fatal error LNK1120: 1 个无法解析的外部命令

demagle出错的符号

class std::unique_ptr<class v8::Platform,struct std::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::unique_ptr<class v8::TracingController,struct std::default_delete<class v8::TracingController> >)" (class std::unique_ptr<class v8::Platform,struct std::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::unique_ptr<class v8::TracingController,struct std::default_delete<class v8::TracingController> >)

似乎在链接阶段发现NewDefaultPlatform这个函数没有实现?这可是官网的Demo程序呀,不可能没实现的
于是赶紧dumpbin一下v8_libplatform.dll.lib,结果如下:

E:\projects\v8\v8\out\x64.debug>dumpbin /EXPORTS v8_libplatform.dll.lib > 1.txt
//1.txt
?NewDefaultPlatform@platform@v8@@YA?AV?$unique_ptr@VPlatform@v8@@U?$default_delete@VPlatform@v8@@@__1@std@@@__1@std@@HW4IdleTaskSupport@12@W4InProcessStackDumping@12@V?$unique_ptr@VTracingController@v8@@U?$default_delete@VTracingController@v8@@@__1@std@@@45@@Z (class std::__1::unique_ptr<class v8::Platform,struct std::__1::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::__1::unique_ptr<class v8::TracingController,struct std::__1::default_delete<class v8::TracingController> >))

前后对比

class std::unique_ptr<class v8::Platform,struct std::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::unique_ptr<class v8::TracingController,struct std::default_delete<class v8::TracingController> >)" (class std::unique_ptr<class v8::Platform,struct std::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::unique_ptr<class v8::TracingController,struct std::default_delete<class v8::TracingController> >)
class std::__1::unique_ptr<class v8::Platform,struct std::__1::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::__1::unique_ptr<class v8::TracingController,struct std::__1::default_delete<class v8::TracingController> >) (class std::__1::unique_ptr<class v8::Platform,struct std::__1::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::__1::unique_ptr<class v8::TracingController,struct std::__1::default_delete<class v8::TracingController> >))

不难看出lib库里的确导出了NewDefaultPlatform符号,但有些不同的是导出库里unique_ptr这种类型都是在std::__1命名空间下,而VS工程里预期导入的符号确是在std命名空间下,问题就在这里。

以前在扒libc++和libstdc++的历史的时候就发现了类似的问题,果然这里出现了。
libc++的库在实现STL的时候使用了inline namespace __1,而libstdc++则没有。好吧,看来V8引擎的编译默认使用了libc++,难怪会生成一个libc++.dll,当时还并未在意来着。

找了找发现libc++的头文件就在\v8\buildtools\third_party\libc++\trunk\include目录下,试着直接把libc++的头文件引入进来,结果编译时报错

1>d:\projects\aps2\aps\c++\stddef.h(45): fatal error C1021: 无效的预处理器命令“include_next”

看来必须得换clang编译器了,可以按照llvm官网指南,一步步来 https://llvm.org/docs/GettingStartedVS.html
稍微看了下比较麻烦,索性换成VS2019,自带clang编译器,然后把将工程转换为CMake工程这样比较简单。

cmake_minimum_required (VERSION 3.8)
project ("test-cmake")
include_directories(./include/c++)
include_directories(./include)
include_directories(./include/v8)
link_directories(./libs)
link_libraries("opengl32.lib" "glew32d" "glfw3" "icui18n.dll.lib" "icuuc.dll.lib" "libglew32d.lib" "lua"  "torque" "v8.dll.lib" "v8_libbase.dll.lib" "v8_libplatform.dll.lib" "zlib.dll.lib")
add_executable (test-cmake "appconfig.cpp" "appconfig.h" "main.cpp")

记得引入libc++的头文件,这下编译终于通过,程序也可以正确执行了

在这里插入图片描述

2020/3/6 更新
发现在Javascript中调用C++函数时,在C++函数中使用IsConstructCall()方法来判断是否构造函数时,出现了指针错误。

void MyObject::New(const FunctionCallbackInfo<Value>& args) {
	Isolate* isolate = args.GetIsolate();
	Local<Context> context = isolate->GetCurrentContext();

	if (args.IsConstructCall()) {
		...
	}

跟踪调试发现

  template <typename T>
  V8_INLINE static T ReadRawField(internal::Address heap_object_ptr,
                                  int offset) {
    internal::Address addr = heap_object_ptr + offset - kHeapObjectTag;
#ifdef V8_COMPRESS_POINTERS
    if (sizeof(T) > kApiTaggedSize) {
      // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
      // fields (external pointers, doubles and BigInt data) are only
      // kTaggedSize aligned so we have to use unaligned pointer friendly way of
      // accessing them in order to avoid undefined behavior in C++ code.
      T r;
      memcpy(&r, reinterpret_cast<void*>(addr), sizeof(T));
      return r;
    }
#endif
    return *reinterpret_cast<const T*>(addr);
  }

TODO里写得也比较清楚,编译期间宏定义V8_COMPRESS_POINTERS是开启的,然后在工程里加上这个宏,程序就能正常运行了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
V8引擎是一款由Google开发的高性能JavaScript引擎,主要用于执行JavaScript代码。而VS2022是微软推出的最新版本的集成开发环境(IDE),用于开发各种类型的应用程序。 关于V8引擎的配置,以下是一些常见的配置步骤: 1. 下载V8源代码:你可以从V8的官方GitHub仓中下载最新的源代码。 2. 安装依赖项:根据操作系统的不同,你需要安装一些必要的依赖项,如Python、C++编译器等。 3. 配置构建:进入V8源代码目录,执行相应的命令来配置构建过程。具体的命令可能因操作系统而异,你可以参考V8官方文档中的指南。 4. 构建V8引擎:执行构建命令来编译V8引擎的源代码。这个过程可能需要一些时间,取决于你的计算机性能和网络速度。 5. 配置项目:在你的项目中,将V8引擎的头文件和文件路径配置到你的构建系统中,以便在代码中使用V8引擎。 关于VS2022的配置,以下是一些常见的步骤: 1. 下载和安装:从微软官方网站下载VS2022,并按照安装向导进行安装。 2. 选择工作负载:在安装过程中,你可以选择不同的工作负载,以适应你的开发需求。例如,选择C++开发工作负载可以包含C++编译器和相关工具。 3. 配置项目:在VS2022中创建或打开你的项目,并根据项目类型进行相应的配置。例如,对于C++项目,你可以设置编译器选项、包含目录、文件路径等。 4. 调试和运行:使用VS2022的调试功能可以方便地调试你的代码。你可以设置断点、观察变量值等。同时,VS2022也提供了运行和构建项目的功能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值