Qt MinGW环境下使用CEF
环境
Clion :2019.3.6
Qt :5.12.12(MinGW 7.3.0)
CEF:cef_binary_87.1.14+ga29e9a3+chromium-87.0.4280.141_windows32
编译libcef_dll_wrapper
修改cmake 文件
修改根目录下的CMakeLists.txt
# 修改cmake 版本
cmake_minimum_required(VERSION 2.8.12.1...3.20.0)
# 设置c++标准
add_definitions("-std=c++11")
# 注释掉测试工程
#if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
# add_subdirectory(tests/cefsimple)
# add_subdirectory(tests/gtest)
# add_subdirectory(tests/ceftests)
#endif()
#if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/cefclient")
# add_subdirectory(tests/cefclient)
#endif()
修改cef_variables.cmake
cef_variables.cmake文件在cmake目录下
主要是修改if(OS_WINDOWS)…endif()节点,因为是用MinGW编译,根据if(OS_LINUX)…endif()内容进行修改。修改原则:删除linux特有的内容,将if(OS_WINDOWS)…endif()节点下windows特有的属性合并进入。最后用修改后的的内容替换if(OS_WINDOWS)…endif()节点。
修改示例:
if(OS_WINDOWS)
# Platform-specific compiler/linker flags.
set(CEF_LIBTYPE STATIC)
list(APPEND CEF_COMPILER_FLAGS
-fno-strict-aliasing # Avoid assumptions regarding non-aliasing of objects of different types
-fPIC # Generate position-independent code for shared libraries
-funwind-tables # Support stack unwinding for backtrace()
-fvisibility=hidden # Give hidden visibility to declarations that are not explicitly marked as visible
--param=ssp-buffer-size=4 # Set the minimum buffer size protected by SSP (security feature, related to stack-protector)
-pipe # Use pipes rather than temporary files for communication between build stages
-pthread # Use the pthread library
-Wall # Enable all warnings
-Werror # Treat warnings as errors
-Wno-missing-field-initializers # Don't warn about missing field initializers
-Wno-unused-parameter # Don't warn about unused parameters
-Wno-error=comment # Don't warn about code in comments
-Wno-comment # Don't warn about code in comments
)
list(APPEND CEF_C_COMPILER_FLAGS
-std=c99 # Use the C99 language standard
)
list(APPEND CEF_CXX_COMPILER_FLAGS
-fno-exceptions # Disable exceptions
-fno-rtti # Disable real-time type information
-fno-threadsafe-statics # Don't generate thread-safe statics
-fvisibility-inlines-hidden # Give hidden visibility to inlined class member functions
-std=gnu++11 # Use the C++11 language standard including GNU extensions
-Wsign-compare # Warn about mixed signed/unsigned type comparisons
)
list(APPEND CEF_COMPILER_FLAGS_DEBUG
-O0 # Disable optimizations
-g # Generate debug information
)
list(APPEND CEF_COMPILER_FLAGS_RELEASE
-O2 # Optimize for maximum speed
-fdata-sections # Enable linker optimizations to improve locality of reference for data sections
-ffunction-sections # Enable linker optimizations to improve locality of reference for function sections
-fno-ident # Ignore the #ident directive
-U_FORTIFY_SOURCE # Undefine _FORTIFY_SOURCE in case it was previously defined
-D_FORTIFY_SOURCE=2 # Add memory and string function protection (security feature, related to stack-protector)
)
list(APPEND CEF_LINKER_FLAGS
-fPIC # Generate position-independent code for shared libraries
-pthread # Use the pthread library
-Wl,--disable-new-dtags # Don't generate new-style dynamic tags in ELF
-Wl,--fatal-warnings # Treat warnings as errors
-Wl,-rpath,. # Set rpath so that libraries can be placed next to the executable
-Wl,-z,noexecstack # Mark the stack as non-executable (security feature)
-Wl,-z,now # Resolve symbols on program start instead of on first use (security feature)
-Wl,-z,relro # Mark relocation sections as read-only (security feature)
)
list(APPEND CEF_LINKER_FLAGS_RELEASE
-Wl,-O1 # Enable linker optimizations
-Wl,--as-needed # Only link libraries that export symbols used by the binary
-Wl,--gc-sections # Remove unused code resulting from -fdata-sections and -function-sections
)
list(APPEND CEF_COMPILER_DEFINES
_FILE_OFFSET_BITS=64 # Allow the Large File Support (LFS) interface to replace the old interface
)
list(APPEND CEF_COMPILER_DEFINES_RELEASE
NDEBUG # Not a debug build
)
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG(-Wno-undefined-var-template COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
if(COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
list(APPEND CEF_CXX_COMPILER_FLAGS
-Wno-undefined-var-template # Don't warn about potentially uninstantiated static members
)
endif()
CHECK_C_COMPILER_FLAG(-Wno-unused-local-typedefs COMPILER_SUPPORTS_NO_UNUSED_LOCAL_TYPEDEFS)
if(COMPILER_SUPPORTS_NO_UNUSED_LOCAL_TYPEDEFS)
list(APPEND CEF_C_COMPILER_FLAGS
-Wno-unused-local-typedefs # Don't warn about unused local typedefs
)
endif()
CHECK_CXX_COMPILER_FLAG(-Wno-literal-suffix COMPILER_SUPPORTS_NO_LITERAL_SUFFIX)
if(COMPILER_SUPPORTS_NO_LITERAL_SUFFIX)
list(APPEND CEF_CXX_COMPILER_FLAGS
-Wno-literal-suffix # Don't warn about invalid suffixes on literals
)
endif()
CHECK_CXX_COMPILER_FLAG(-Wno-narrowing COMPILER_SUPPORTS_NO_NARROWING)
if(COMPILER_SUPPORTS_NO_NARROWING)
list(APPEND CEF_CXX_COMPILER_FLAGS
-Wno-narrowing # Don't warn about type narrowing
)
endif()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
list(APPEND CEF_CXX_COMPILER_FLAGS
-Wno-attributes # The cfi-icall attribute is not supported by the GNU C++ compiler
)
endif()
if(PROJECT_ARCH STREQUAL "x86_64")
# 64-bit architecture.
list(APPEND CEF_COMPILER_FLAGS
-m64
-march=x86-64
)
list(APPEND CEF_LINKER_FLAGS
-m64
)
elseif(PROJECT_ARCH STREQUAL "x86")
# 32-bit architecture.
list(APPEND CEF_COMPILER_FLAGS
-msse2
-mfpmath=sse
-mmmx
-m32
)
list(APPEND CEF_LINKER_FLAGS
-m32
)
endif()
# Standard libraries.
set(CEF_STANDARD_LIBS
X11
)
# Standard libraries.
set(CEF_STANDARD_LIBS
comctl32.lib
rpcrt4.lib
shlwapi.lib
ws2_32.lib
)
# CEF directory paths.
set(CEF_RESOURCE_DIR "${_CEF_ROOT}/Resources")
set(CEF_BINARY_DIR "${_CEF_ROOT}/$<CONFIGURATION>")
set(CEF_BINARY_DIR_DEBUG "${_CEF_ROOT}/Debug")
set(CEF_BINARY_DIR_RELEASE "${_CEF_ROOT}/Release")
# CEF library paths.
set(CEF_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/libcef.lib")
set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/libcef.lib")
# List of CEF binary files.
set(CEF_BINARY_FILES
chrome_elf.dll
d3dcompiler_47.dll
libcef.dll
libEGL.dll
libGLESv2.dll
snapshot_blob.bin
v8_context_snapshot.bin
swiftshader
)
# List of CEF resource files.
set(CEF_RESOURCE_FILES
cef.pak
cef_100_percent.pak
cef_200_percent.pak
cef_extensions.pak
devtools_resources.pak
icudtl.dat
locales
)
endif()
修改部分代码
include\internal\cef_string_wrappers.h
// 36行增加
#if defined(__MINGW32__)
#include <cstring>
#endif
include\base\internal\cef_atomicops_x86_msvc.h
// 82行修改
#if !(defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(__MINGW32__)
include\base\cef_atomicops.h
// 179行修改
#if defined(OS_WIN) && (defined(COMPILER_MSVC) || defined(__MINGW32__)) && defined(ARCH_CPU_X86_FAMILY)
include\base\cef_bind_helpers.h
// 275 行修改
#if defined(OS_WIN) && defined (COMPILER_MSVC)
// 280 行修改
#if defined(OS_WIN) && defined (COMPILER_MSVC)
// 两外一种修改方式:注释掉宏判断
//#if defined(OS_WIN)
//#pragma warning(push)
//#pragma warning(disable : 4624)
//#endif
struct Base : public T, public BaseMixin {};
//#if defined(OS_WIN)
//#pragma warning(pop)
//#endif
如果需要编译64位版本,将__MINGW32__宏改为__MINGW64__即可(前提是你下载的是win64版源码)
如果需要编译高版本的CEF库,可以先编译,然后根据错误提示修改。(原则:CEF没有提供MinGW的编译方式,需要在原来的MSVC的基础行修改,错误一般是由于MSVC宏引起的)
编译
做完以上工作后可以直接编译了,我这里选择的是编译Relese版,编译完成后可以在cmake-build-release\libcef_dll_wrapper目录下找到libcef_dll_wrapper.a文件。
使用
- 新建Qt工程cef_client,将CEF中tests\cefsimple目录下的simple_app.cc,simple_app.h,simple_handler.cc,simple_handler.h,simple_handler_win.cc文件复制到cef_client目录下
- 将CEF下的inclue目录复制到cef_client/cef目录下
- 将libcef_dll_wrapper.a复制到cef_client/cef目录下
- 将CEF中Release目录下的libcef.lib复制到cef_client/cef目录下并修改扩展名为.a(是不是很意外,其实MinGW的链文件.a与VC的连接文件.lib本质上差不多,MinGW可以兼容.lib连接文件(前提是.lib中不包含vc特有的特性),如果要使用高版本的CEF库,可能需要升级MinGW的版本)
.pro文件
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++14
INCLUDEPATH +=
$$PWD/cef/include
SOURCES += \
main.cpp \
MainWindow.cpp \
simple_app.cc \
simple_handler.cc \
simple_handler_win.cc
HEADERS += \
MainWindow.h \
simple_app.h \
simple_handler.h
FORMS += \
MainWindow.ui
win32: LIBS += -L$$PWD/cef/ -lcef_dll_wrapper
win32: LIBS += -L$$PWD/cef/ -lcef
INCLUDEPATH += $$PWD/cef
DEPENDPATH += $$PWD/cef
编译完成后将CEF资源文件,和libcef.dll等相关库(Release目录下除过.lib文件)复制到编译好的程序目录
simple_app.cc文件中的OnContextInitialized函数,修改如下
void SimpleApp::OnContextInitialized() {
return;
}
否则启动后会出现两个浏览器窗口
## main.cpp
#include "MainWindow.h"
#include "simple_app.h"
#include "simple_handler.h"
#include <QApplication>
bool CefInit()
{
CefEnableHighDPISupport();
CefSettings settings;
settings.no_sandbox = true;
settings.multi_threaded_message_loop = true;
HINSTANCE inc = GetModuleHandle(NULL);
CefMainArgs mainArgs(inc);
CefRefPtr<CefApp> app;
app = new SimpleApp;
return CefInitialize(mainArgs, settings, app.get(), NULL);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CefInit();
MainWindow w;
w.showMaximized();
a.exec();
return 0;
}
MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) {
ui->setupUi(this);
initBrowser();
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::initBrowser() {
CefWindowInfo cefWndInfo;
QString strUrl = "https://www.baidu.com/";
HWND wnd = (HWND)ui->fmBrowser->winId();
RECT winRect;
QDesktopWidget* pDeskTop = QApplication::desktop();
QRect qtRect = pDeskTop->screenGeometry();
winRect.left = qtRect.left();
winRect.top = qtRect.top();
winRect.right = qtRect.right();
winRect.bottom = qtRect.bottom();
cefWndInfo.SetAsChild(wnd, winRect);
CefBrowserSettings cefBrowSetting;
cef_browser_ev_ = CefRefPtr<SimpleHandler>(new SimpleHandler(true));
CefBrowserHost::CreateBrowser(cefWndInfo, cef_browser_ev_, strUrl.toStdString(), cefBrowSetting, nullptr,nullptr);
emit resize(qtRect.width(), qtRect.height());
}
void MainWindow::resizeEvent(QResizeEvent *event) {
if (cef_browser_ev_.get() == NULL) {
return;
}
QRect qtRect = ui->fmBrowser->rect();
const BrowserList browList = cef_browser_ev_->GetBrowserList();
if (!browList.empty()) {
HWND wnd = browList.front()->GetHost()->GetWindowHandle();
::MoveWindow(wnd, qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height(), true);
}
}