AWTK 全称为 Toolkit AnyWhere,是 ZLG 倾心打造的一套基于 C 语言开发的 GUI 框架。旨在为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎,并支持跨平台同步开发,一次编程,终生使用。
主要特色:
上面简单介绍了一下ZLG的GUI,下面开始填坑。
填坑之前先说一下为啥给自己挖坑。在windows下搞C语言设计开发,可能更多人会选择VS,但是编译AWTK需要比较高版本的VS,这对我来说体验不是很好,VS的安装包体积实在是太大了,启动又慢,我只需要用到编译代码这一个基础功能,显然VS不是理想的选择。
后来在AWTK的帮助文档里看到,AWTK可以使用MinGW作为编译工具,而且官方提供了使用方法,遂决定试用一下。实践结果告诉我,官方的使用方法根本编译不过去,这才有了填坑记录。
系统:WIN7 X64 旗舰版
硬件:i5 M560+3G内存+64G固态
软件:AWTK-Designer-x64-0.1.3-Preview-Setup python-3.8.3-amd64 awtk-scons-mingw
1、ZLG官方提供了一个GUI界面设计编辑器,需要注册使用,下载地址:https://awtk.zlg.cn/
点击 登录 按钮下方的 客户端下载 即可。下载得到的是一个64位的安装程序,只能在64位系统下使用,下面介绍安装过程。
双击AWTK-Designer安装包进行安装,默认安装到C盘。
AWTK-Designer安装完成后,可以在SDK文件夹下找到AWTK的全部源码,无需另外下载,但有可能不是最新的版本,如果需要最新的源码,需要到主源码仓库:https://github.com/zlgopen/awtk 进行更新。
2、从python官网下载64位的安装包,地址:https://www.python.org/downloads/windows/
双击安装包,在 Add Python 3.8 to PATH 前打勾,然后选择自定义安装。
修改安装路径
其他选项保持默认。
下载scons,地址:https://scons.org/pages/download.html
解压到任意目录,打开CMD,进入scons目录,输入
python setup.py install
进行安装。
3、AWTK提供了MinGW,地址:https://github.com/zlgopen/awtk-scons-mingw
将MinGW文件夹解压到C盘,然后添加环境变量。
CMD窗口输入
gcc -v
可以看到,ZLG提供的MinGW是32位的。
4、目前看,工具是备齐了,编译试试看,有不足的地方再补充。
先来看看awtk-scons-mingw的官方说明
# awtk-scons-mingw
build awtk with scons and mingw on windows* 将 awtk 和本项目取到同一级目录
```
cd c:\zlgopen
git clone https://github.com/zlgopen/awtk.git
git clone https://github.com/zlgopen/awtk-scons-mingw.git
```* 安装 scons,并设置好 MinGW 的 Path 环境变量
```
C:\zlgopen\awtk-scons-mingw\MinGW\bin
```![mingw_path](docs/images/mingw_path.png)
* 修改 awtk 的编译配置 awtk_config.py,使用 mingw 作为编译工具
```
NATIVE_WINDOW='sdl'
TOOLS_NAME = ''
TOOLS_NAME = 'mingw' # 把该行前面的注释去掉
```* 进入目录 awtk,执行 scons 编译
```
cd awtk
scons
```* 编译其他的 Demo
```
cd c:\zlgopen
git clone https://github.com/zlgopen/awtk-examples.git
cd awtk-examples\Chart-Demo
scons
```
我们按照官方指示,用记事本打开C:\AWTK\SDK\awtk\awtk_config.py,找到
NATIVE_WINDOW='sdl'
TOOLS_NAME = ''
# TOOLS_NAME = 'mingw'
修改为
NATIVE_WINDOW='sdl'
TOOLS_NAME = ''
TOOLS_NAME = 'mingw'
在C:\AWTK\SDK\awtk目录下打开CMD,输入scons,执行编译。随着CPU风扇一阵狂转,命令停在了下面这个位置
gcc -o src\platforms\pc\fs_os.o -c -DWINDOWS -D_CONSOLE -g -Wall -DTK_ROOT=\"C:\
\AWTK\\SDK\\awtk\" -DWITH_ASSET_LOADER -DWITH_FS_RES -DWITH_ASSET_LOADER_ZIP -DS
TBTT_STATIC -DSTB_IMAGE_STATIC -DWITH_STB_IMAGE -DWITH_SOCKET -DWITH_VGCANVAS -D
WITH_UNICODE_BREAK -DWITH_DESKTOP_STYLE -DSDL2 -DHAS_STD_MALLOC -DWITH_SDL -DHAS
_STDIO -DHAVE_STDIO_H -DWITH_STB_FONT -DWITH_BITMAP_BGRA -DWITH_NANOVG_SOFT -DWI
TH_FB_BGR565=1 -DWITH_NANOVG_AGGE -DWITH_DOUBLE_FLOAT -DUNICODE -DSDL_REAL_API -
DSDL_HAPTIC_DISABLED -DSDL_SENSOR_DISABLED -DSDL_JOYSTICK_DISABLED -D__STDC_LIMI
T_MACROS -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -D_HAS_EXCEPTIONS=0 -D_
HAS_ITERATOR_DEBUGGING=0 -D_ITERATOR_DEBUG_LEVEL=0 -D_SCL_SECURE=0-D_SECURE_SCL=
0 -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE
-I. -Isrc -I3rd -Isrc\ext_widgets -I3rd\pixman -I3rd\cairo -I3rd\bgfx\bgfx\incl
ude -I3rd\bgfx\bx\include -I3rd\bgfx\bimg\include -I3rd\agge -I3rd\agg\include -
I3rd\nanovg -I3rd\nanovg\gl -I3rd\nanovg\base -I3rd\nanovg\agge -I3rd\nanovg\bgf
x -I3rd\SDL\src -I3rd\SDL\include -I3rd\agge\src -I3rd\agge\include -I3rd\gpinyi
n\include -I3rd\libunibreak -I3rd\gtest\googletest -I3rd\gtest\googletest\includ
e -Itools src\platforms\pc\fs_os.c
=====
b"src\\platforms\\pc\\fs_os.c: In function 'fs_os_file_exist':\nsrc\\platforms\\
pc\\fs_os.c:189:21: error: storage size of 'st' isn't known\n struct _stat64i3
2 st;\n ^~\nsrc\\platforms\\pc\\fs_os.c:189:21: warning: unu
sed variable 'st' [-Wunused-variable]\nsrc\\platforms\\pc\\fs_os.c: In function
'fs_os_dir_exist':\nsrc\\platforms\\pc\\fs_os.c:296:21: error: storage size of '
st' isn't known\n struct _stat64i32 st;\n ^~\nsrc\\platfor
ms\\pc\\fs_os.c:296:21: warning: unused variable 'st' [-Wunused-variable]\nsrc\\
platforms\\pc\\fs_os.c: In function 'fs_os_get_file_size':\nsrc\\platforms\\pc\\
fs_os.c:327:21: error: storage size of 'st' isn't known\n struct _stat64i32 st
;\n ^~\nsrc\\platforms\\pc\\fs_os.c:327:21: warning: unused
variable 'st' [-Wunused-variable]\nsrc\\platforms\\pc\\fs_os.c: In function 'fs_
os_get_cwd':\nsrc\\platforms\\pc\\fs_os.c:390:33: warning: passing argument 2 of
'GetCurrentDirectoryW' from incompatible pointer type [-Wincompatible-pointer-t
ypes]\n GetCurrentDirectory(MAX_PATH, path);\n
^~~~\nIn file included from c:\\mingw\\include\\windows.h:44,\n
from src\\platforms\\pc\\fs_os.c:6:\nc:\\mingw\\include\\winbase.h:1669:54: not
e: expected 'LPWSTR' {aka 'short unsigned int *'} but argument is of type 'char
*'\n WINBASEAPI DWORD WINAPI GetCurrentDirectoryW (DWORD, LPWSTR);\n
^~~~~~\nsrc\\platforms\\pc\\fs_os.c: I
n function 'fs_os_stat':\nsrc\\platforms\\pc\\fs_os.c:405:21: error: storage siz
e of 'st' isn't known\n struct _stat64i32 st;\n ^~\nsrc\\p
latforms\\pc\\fs_os.c:405:21: warning: unused variable 'st' [-Wunused-variable]\
nsrc\\platforms\\pc\\fs_os.c: In function 'fs_os_get_file_size':\nsrc\\platforms
\\pc\\fs_os.c:348:1: warning: control reaches end of non-void function [-Wreturn
-type]\n }\n ^\n"
=====
scons: *** [src\platforms\pc\fs_os.o] Error 1
scons: building terminated because of errors.
咱们把报错的这几句整理一下,方便查看
=====
b"src\\platforms\\pc\\fs_os.c: In function 'fs_os_file_exist':
src\\platforms\\pc\\fs_os.c:189:21: error: storage size of 'st' isn't known
struct _stat64i32 st;
^~
src\\platforms\\pc\\fs_os.c:189:21: warning: unused variable 'st' [-Wunused-variable]
src\\platforms\\pc\\fs_os.c: In function'fs_os_dir_exist':
src\\platforms\\pc\\fs_os.c:296:21: error: storage size of 'st' isn't known
struct _stat64i32 st;
^~
src\\platforms\\pc\\fs_os.c:296:21: warning: unused variable 'st' [-Wunused-variable]
src\\platforms\\pc\\fs_os.c: In function 'fs_os_get_file_size':
src\\platforms\\pc\\fs_os.c:327:21: error: storage size of 'st' isn't known
struct _stat64i32 st;
^~
src\\platforms\\pc\\fs_os.c:327:21: warning: unusedvariable 'st' [-Wunused-variable]
src\\platforms\\pc\\fs_os.c: In function 'fs_os_get_cwd':
src\\platforms\\pc\\fs_os.c:390:33: warning: passing argument 2 of 'GetCurrentDirectoryW' from incompatible pointer type [-Wincompatible-pointer-types]
GetCurrentDirectory(MAX_PATH, path);
^~~~
In file included from c:\\mingw\\include\\windows.h:44,
from src\\platforms\\pc\\fs_os.c:6:
c:\\mingw\\include\\winbase.h:1669:54: note: expected 'LPWSTR' {aka 'short unsigned int *'} but argument is of type 'char*'
WINBASEAPI DWORD WINAPI GetCurrentDirectoryW (DWORD, LPWSTR);
^~~~~~
src\\platforms\\pc\\fs_os.c: In function 'fs_os_stat':
src\\platforms\\pc\\fs_os.c:405:21: error: storage size of 'st' isn't known
struct _stat64i32 st;
^~
src\\platforms\\pc\\fs_os.c:405:21: warning: unused variable 'st' [-Wunused-variable]
src\\platforms\\pc\\fs_os.c: In function 'fs_os_get_file_size':
src\\platforms\\pc\\fs_os.c:348:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
"
=====
scons: *** [src\platforms\pc\fs_os.o] Error 1
scons: building terminated because of errors.
很明显,在C:\AWTK\SDK\awtk\src\platforms\pc\fs_os.c的第189、296、327、405行出现了
error: storage size of 'st' isn't known
这样的错误。看来编译器不能准确识别st这个变量,我们来看看st是如何定义的。
struct _stat64i32 st;
这四处的定义都一样。struct好理解,那_stat64i32是啥?经过查找,_stat64i32的定义在C:\MinGW\include\sys\stat.h中
/* The structure manipulated and returned by stat() and fstat(); note that
* expansion of the macro provided below will yield variants of struct stat
* to conform with Microsoft's usage, (and POSIX usage up to and including
* POSIX.1-2001, but NOT the extended specification of POSIX.1-2008).
*
* NOTE: If called on a directory the values in the time fields are not only
* invalid, they will cause localtime et. al. to return NULL. And calling
* asctime with a NULL pointer causes an Invalid Page Fault. So watch it!
*/
#define __struct_stat_defined(__st_off_t, __st_time_t) \
{ _dev_t st_dev; /* Equivalent to drive number 0=A 1=B ... */ \
_ino_t st_ino; /* Always zero ? */ \
_mode_t st_mode; /* See above constants */ \
short st_nlink; /* Number of links. */ \
short st_uid; /* User: Maybe significant on NT ? */ \
short st_gid; /* Group: Ditto */ \
_dev_t st_rdev; /* Seems useless (not even filled in) */ \
__st_off_t st_size; /* File size in bytes */ \
__st_time_t st_atime; /* Access time (always 00:00 on FAT) */ \
__st_time_t st_mtime; /* Modified time */ \
__st_time_t st_ctime; /* Creation time */ \
}
#if defined __MSVCRT__
/* This variant of struct stat is required to support the use of the
* _stati64() function, which is provided by MSVCRT.DLL, but was not
* present in CRTDLL.DLL...
*/
struct _stati64 __struct_stat_defined( __off64_t, time_t );
#if __MSVCRT_VERSION__ >= __MSVCR61_DLL || _WIN32_WINNT >= _WIN32_WINNT_WIN2K
/* ...while this supports the use of the _stat64() function, introduced
* by MSVCR61.DLL, and subsequently added to MSVCRT.DLL for releases from
* Win2K onwards...
*/
struct __stat64 __struct_stat_defined( __off64_t, __time64_t );
#if __MSVCRT_VERSION__ >= __MSVCR80_DLL
/* ...and these are specific to additional function variants, added to
* the non-free MSVCR80.DLL, and its later derivatives, but not present
* in MSVCRT.DLL (or CRTDLL.DLL).
*/
struct __stat32 __struct_stat_defined( __off32_t, __time32_t );
struct _stat32i64 __struct_stat_defined( __off64_t, __time32_t );
struct _stat64i32 __struct_stat_defined( __off32_t, __time64_t );
#endif /* __MSVCRT_VERSION__ >= __MSVCR80_DLL */
#endif /* __MSVCRT_VERSION__ >= __MSVCR61_DLL */
#endif /* __MSVCRT__ */
也就是说,struct _stat64i32 __struct_stat_defined( __off32_t, __time64_t );被声明的条件必须是__MSVCRT_VERSION__ >= __MSVCR80_DLL,那么__MSVCRT_VERSION__ 是多少呢?
查看C:\MinGW\include\msvcrtver.h
/* When it is intended to link an application with any one of the
* MSVC version specific MSVCRxx.DLL libraries, rather than with the
* OS default MSVCRT.DLL, the particular substitute MSVCRxx.DLL may
* be specified as any one of the following...
*/
#define __MSVCR60_DLL 0x0600
#define __MSVCR61_DLL 0x0601
#define __MSVCR70_DLL 0x0700
#define __MSVCR71_DLL 0x0701
#define __MSVCR80_DLL 0x0800
#define __MSVCR90_DLL 0x0900
#define __MSVCR100_DLL 0x1000
#define __MSVCR110_DLL 0x1100
#define __MSVCR120_DLL 0x1200
#ifndef __MSVCRT_VERSION__
/* This may be set, when the intent is to link with any of the above
* non-freely distributable MSVCRxx.DLL libraries, rather than with the
* pseudo-free MSVCRT.DLL provided as an OS component. High byte is the
* major version number, low byte is the minor; however, users are advised
* to use custom GCC specs files to set this, while also substituting the
* appropriate library in place of MSVCRT.DLL, rather than to simply set
* it directly.
*
* It should be noted that __MSVCRT_VERSION__ is NOT a good indicator of
* evolving MSVCRT.DLL features; that is better accomplished by using the
* NTDDI_VERSION setting from the Windows API. Thus, users of MSVCRT.DLL
* should NOT set __MSVCRT_VERSION__, leaving us to establish a default,
* equivalent to MSVCR60.DLL, which seems reasonably well aligned with
* the feature set of the earliest MSVCRT.DLL version we support.
*/
# define __MSVCRT_VERSION__ __MSVCR60_DLL
#endif
可知__MSVCRT_VERSION__ 的默认值是__MSVCR60_DLL,说明MinGW 默认链接的是 msvcrt.dll,显然不满足__MSVCRT_VERSION__ >= __MSVCR80_DLL的要求。那么,我的windows系统里到底有哪些版本的MSVCRxx.DLL呢?
由此可见,我的C:\Windows\System32下只有MSVCR100.DLL、MSVCR110.DLL、MSVCR120.DLL这三个。当然,msvcrt.dll是肯定有的。
解决这个问题有两个思路,一是自行定义__MSVCRT_VERSION__的值,让它大于等于 __MSVCR80_DLL,比如我这里可以令__MSVCRT_VERSION__=__MSVCR100_DLL,用记事本打开C:\AWTK\SDK\awtk\awtk_config.py,找到
elif TOOLS_NAME == 'mingw' :
OS_LIBS=['kernel32', 'gdi32', 'user32', 'winmm','imm32','version','shell32','ole32','Oleaut32','Advapi32','oleaut32','uuid','stdc++']
OS_FLAGS='-DWINDOWS -D_CONSOLE -g -Wall'
COMMON_CFLAGS=COMMON_CFLAGS+' -std=gnu99 '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_DOUBLE_FLOAT -DUNICODE '
修改为
elif TOOLS_NAME == 'mingw' :
OS_LIBS=['kernel32', 'gdi32', 'user32', 'winmm','imm32','version','shell32','ole32','Oleaut32','Advapi32','oleaut32','uuid','stdc++']
OS_FLAGS='-DWINDOWS -D_CONSOLE -g -Wall'
COMMON_CFLAGS=COMMON_CFLAGS+' -std=gnu99 '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_DOUBLE_FLOAT -DUNICODE -D__MSVCRT_VERSION__=__MSVCR100_DLL '
但是这个思路有个弊端,那就是要求系统必须有指定版本的MSVCRxx.DLL,编译出来的程序可能无法顺利在其他电脑上运行,要不就是程序所在的目录必须附带指定版本的MSVCRxx.DLL。
第二个思路还是利用msvcrt.dll,这个动态库windows系统都有,而且MinGW默认也是链接它。打开C:\AWTK\SDK\awtk\src\platforms\pc\fs_os.c,搜索_stat64i32并替换为_stati64,保存。
顺利解决掉一个问题了,继续编译。还是scons
undefined reference to `WinMain@16'
这个错误很有意思,找不到WinMain函数,也找不到main函数。我们来看看C:\AWTK\SDK\awtk\tools\svg_gen\bsvg_gen.cc的源码
/**
* File: bsvg_gen.cc
* Author: AWTK Develop Team
* Brief: bsvg_gen
*
* Copyright (c) 2018 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-11-19 Li XianJing created
*
*/
#include "tkc/mem.h"
#include "tkc/fs.h"
#include "common/utils.h"
#include "base/assets_manager.h"
#include "svg/svg_to_bsvg.h"
static ret_t bsvg_gen(const char* input_file, const char* output_file, bool_t bin) {
uint32_t* out = NULL;
uint32_t size = 0;
uint32_t out_size = 0;
char* xml = (char*)file_read(input_file, &size);
if (svg_to_bsvg(xml, size, &out, &out_size) == RET_OK) {
if (bin) {
write_file(output_file, out, out_size);
} else {
output_res_c_source(output_file, ASSET_TYPE_IMAGE, ASSET_TYPE_IMAGE_BSVG, (uint8_t*)out,
out_size);
}
}
TKMEM_FREE(xml);
return RET_OK;
}
int wmain(int argc, wchar_t* argv[]) {
bool_t output_bin = argc > 3;
const char* in_filename = NULL;
const char* out_filename = NULL;
TKMEM_INIT(4 * 1024 * 1024)
if (argc < 3) {
printf("Usage: %S svg_filename bsvg_filename [bin]\n", argv[0]);
return 0;
}
str_t in_file;
str_t out_file;
str_init(&in_file, 0);
str_init(&out_file, 0);
str_from_wstr(&in_file, argv[1]);
str_from_wstr(&out_file, argv[2]);
in_filename = in_file.str;
out_filename = out_file.str;
exit_if_need_not_update(in_filename, out_filename);
bsvg_gen(in_filename, out_filename, output_bin);
str_reset(&in_file);
str_reset(&out_file);
return 0;
}
#include "common/main.inc"
有个wmain函数,但这不是标准的入口函数。源码最后一行写着#include "common/main.inc",我们来看看C:\AWTK\SDK\awtk\tools\common\main.inc的源码
#include "common/utils.h"
#ifndef WIN32
int main(int argc, char* argv[]) {
int ret = 0;
wchar_t** argvw = argvw_create(argc, argv);
ret = wmain(argc, argvw);
argvw_destroy(argvw);
return ret;
}
#endif /*WIN32*/
咦,这里有main函数呀,在main函数内部调用了wmain函数。难道是#ifndef WIN32造成的?从上文fs_os.c的报错来看,WIN32应该是定义过了,不然也不会报错
既然WIN32被定义过,那么#ifndef WIN32便不成立,main函数也不会被编译。看到这里,大体上可以猜测作者的意图是只有编译控制台程序时才编译main函数,但是你好歹给个WinMain函数呀。返回头来,咱们再看看bsvg_gen.cc是要实现什么功能的
#### 1.BSVG 生成工具。
```
./bin/bsvggen svg_filename bsvg_filename [bin]
```* svg\_filename svg文件名。
* bsvg\_filename bsvg文件名。
* bin 是否生成二进制格式(目标平台有文件系统时使用),缺省生成C语言常量数组。
可见,这应该就是标准的控制台程序,我们尝试把#ifndef WIN32和#endif注释掉,再次编译看看。OK,顺利生成了bsvggen.exe。不过,又出现了新问题。
gcc -o bin\demo1.exe demos\demo1_app.o -Llib -lassets -lawtk -lextwidgets -lwidg
ets -lbase -lgpinyin -lminiz -ltkc -llinebreak -lnanovg-agge -lnanovg -lagge -lS
DL2 -lglad -lkernel32 -lgdi32 -luser32 -lwinmm -limm32 -lversion -lshell32 -lole
32 -lOleaut32 -lAdvapi32 -loleaut32 -luuid -lstdc++
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: lib/libtkc
.a(event_source_manager_default.o): in function `_FD_ISSET':
c:/mingw/include/winsock.h:165: undefined reference to `__WSAFDIsSet@8'
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: lib/libtkc
.a(event_source_manager_default.o): in function `event_source_manager_default_di
spatch_fds':
C:\AWTK\SDK\awtk/src/tkc/event_source_manager_default.c:79: undefined reference
to `select@20'
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: lib/libtkc
.a(event_source_manager_default.o): in function `_FD_ISSET':
c:/mingw/include/winsock.h:165: undefined reference to `__WSAFDIsSet@8'
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: c:/mingw/b
in/../lib/gcc/mingw32/8.2.0/../../../libmingw32.a(main.o):(.text.startup+0xb0):
undefined reference to `WinMain@16'
collect2.exe: error: ld returned 1 exit status
scons: *** [bin\demo1.exe] Error 1
scons: building terminated because of errors.
这里面有几个错误,我们分别来看。先看C:\AWTK\SDK\awtk/src/tkc/event_source_manager_default.c的源码
/**
* File: event_source_manager_default.c
* Author: AWTK Develop Team
* Brief: event manager_default manager_default
*
* Copyright (c) 2019 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2019-09-29 Li XianJing created
*
*/
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif /*WIN32_LEAN_AND_MEAN*/
#include "tkc/mem.h"
#include "tkc/platform.h"
#include "tkc/event_source_manager_default.h"
#ifdef WITH_SOCKET
#ifdef WIN32
#include "windows.h"
#include
#include
typedef int socklen_t;
#else
#include
#include
#include
#include
#endif /*WIN32*/
static ret_t event_source_manager_default_dispatch_fds(event_source_manager_t* manager,
uint32_t sleep_time) {
fd_set fdsr;
uint32_t i = 0;
uint32_t n = 0;
int32_t fd = 0;
int32_t ret = 0;
int32_t max_fd = 0;
struct timeval tv = {0, 0};
event_source_t* iter = NULL;
event_source_t** sources = NULL;
return_value_if_fail(manager != NULL, 0);
FD_ZERO(&fdsr);
tv.tv_sec = sleep_time / 1000;
tv.tv_usec = (sleep_time % 1000) * 1000;
n = manager->dispatching_sources.size;
sources = (event_source_t**)(manager->dispatching_sources.elms);
for (i = 0; i < n; i++) {
iter = sources[i];
fd = event_source_get_fd(iter);
if (fd >= 0) {
FD_SET(fd, &fdsr);
if (fd > max_fd) {
max_fd = fd;
}
}
}
if (max_fd == 0) {
return RET_OK;
}
ret = select(max_fd + 1, &fdsr, NULL, NULL, &tv);
if (ret < 0) {
perror("select");
return RET_FAIL;
} else if (ret == 0) {
return RET_TIMEOUT;
}
for (i = 0; i < n; i++) {
iter = sources[i];
fd = event_source_get_fd(iter);
if (fd >= 0) {
if (FD_ISSET(fd, &fdsr)) {
ret_t r = event_source_dispatch(iter);
if (r == RET_REMOVE) {
event_source_manager_remove(manager, iter);
}
}
}
}
return RET_OK;
}
#else
static ret_t event_source_manager_default_dispatch_fds(event_source_manager_t* manager,
uint32_t sleep_time) {
return RET_OK;
}
#endif /*WITH_SOCKET*/
还是从报错情况来分析,#ifdef WITH_SOCKET和#ifdef WIN32应该都是成立的(在awtk_config.py中有WITH_SOCKET的定义),那么必定有
#include "windows.h"
#include
#include
然而在MinGW中,要想使用winsock2,应该在链接时添加参数-lws2_32来链接到ws2_32.dll,所以解决这里的问题也有两个思路,要么添加链接参数-lws2_32,要么在awtk_config.py去掉WITH_SOCKET的定义。我们这里采用前者,用记事本打开C:\AWTK\SDK\awtk\awtk_config.py,找到
elif TOOLS_NAME == 'mingw' :
OS_LIBS=['kernel32', 'gdi32', 'user32', 'winmm','imm32','version','shell32','ole32','Oleaut32','Advapi32','oleaut32','uuid','stdc++']
修改为
elif TOOLS_NAME == 'mingw' :
OS_LIBS=['kernel32', 'gdi32', 'user32', 'winmm','imm32','version','shell32','ole32','Oleaut32','Advapi32','oleaut32','uuid','stdc++','ws2_32']
再编译一下试试
gcc -o bin\demo1.exe demos\demo1_app.o -Llib -lassets -lawtk -lextwidgets -lwidg
ets -lbase -lgpinyin -lminiz -ltkc -llinebreak -lnanovg-agge -lnanovg -lagge -lS
DL2 -lglad -lkernel32 -lgdi32 -luser32 -lwinmm -limm32 -lversion -lshell32 -lole
32 -lOleaut32 -lAdvapi32 -loleaut32 -luuid -lstdc++ -lws2_32
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: c:/mingw/b
in/../lib/gcc/mingw32/8.2.0/../../../libmingw32.a(main.o):(.text.startup+0xb0):
undefined reference to `WinMain@16'
collect2.exe: error: ld returned 1 exit status
scons: *** [bin\demo1.exe] Error 1
scons: building terminated because of errors.
嗯。。。错误似曾相识(上文)。还是从源码入手,先看C:\AWTK\SDK\awtk\demos\demo1_app.c,最关键的还是这一句
#include "awtk_main.inc"
打开C:\AWTK\SDK\awtk\src\awtk_main.inc
/**
* File: awtk_main.c
* Author: AWTK Develop Team
* Brief: awtk main
*
* Copyright (c) 2018 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2018-02-16 Li XianJing created
*
*/
#include "awtk.h"
BEGIN_C_DECLS
extern ret_t assets_init();
END_C_DECLS
#ifndef LCD_WIDTH
#define LCD_WIDTH 320
#endif /*LCD_WIDTH*/
#ifndef LCD_HEIGHT
#define LCD_HEIGHT 480
#endif /*LCD_HEIGHT*/
#ifndef APP_TYPE
#define APP_TYPE APP_SIMULATOR
#endif /*APP_TYPE*/
#ifndef GLOBAL_INIT
#define GLOBAL_INIT()
#endif /*GLOBAL_INIT*/
#ifndef GLOBAL_EXIT
#define GLOBAL_EXIT()
#endif /*GLOBAL_EXIT*/
#ifndef APP_NAME
#define APP_NAME "awtk"
#endif /*APP_NAME*/
#ifndef APP_RES_ROOT
#define APP_RES_ROOT NULL
#endif /*APP_RES_ROOT*/
#ifdef IOS
#include "base/asset_loader_zip.h"
#endif /*IOS*/
#ifdef USE_GUI_MAIN
int gui_app_start(int lcd_w, int lcd_h) {
tk_init(lcd_w, lcd_h, APP_MOBILE, APP_NAME, APP_RES_ROOT);
#elif defined(MOBILE_APP) && defined(WITH_SDL)
int SDL_main(int argc, char* argv[]) {
int32_t lcd_w = 0;
int32_t lcd_h = 0;
tk_init(lcd_w, lcd_h, APP_MOBILE, APP_NAME, APP_RES_ROOT);
system_info_set_default_font(system_info(), "default_full");
#elif defined(WIN32)
#include
#define MAX_ARGV 7
static void command_line_to_argv(char* lpcmdline, const char* argv[MAX_ARGV], int32_t* argc) {
int32_t i = 1;
char* p = lpcmdline;
argv[0] = "awtk.exe";
if (!*p) {
argv[1] = NULL;
return;
}
for (i = 1; i < MAX_ARGV; i++) {
argv[i] = p;
if (*p == '\"') {
argv[i] = p + 1;
p = strchr(p + 1, '\"');
if (p == NULL) break;
*p++ = '\0';
if (*p == 0) break;
} else {
p = strchr(p, ' ');
}
if (p == NULL) {
break;
}
while (*p == ' ') {
*p++ = '\0';
}
}
*argc = i + 1;
return;
}
int WINAPI wWinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPWSTR lpcmdline, int ncmdshow) {
str_t str;
int argc = 1;
char* argv[MAX_ARGV];
int32_t lcd_w = LCD_WIDTH;
int32_t lcd_h = LCD_HEIGHT;
str_init(&str, 1024);
str_from_wstr(&str, lpcmdline);
command_line_to_argv(str.str, argv, &argc);
TK_ENABLE_CONSOLE();
#ifdef ON_CMD_LINE
ON_CMD_LINE(argc, argv);
#else
if (argc >= 2) {
lcd_w = tk_atoi(argv[1]);
}
if (argc >= 3) {
lcd_h = tk_atoi(argv[2]);
}
#endif /*ON_CMD_LINE*/
tk_init(lcd_w, lcd_h, APP_TYPE, APP_NAME, APP_RES_ROOT);
#else
int main(int argc, char* argv[]) {
int32_t lcd_w = LCD_WIDTH;
int32_t lcd_h = LCD_HEIGHT;
#ifdef ON_CMD_LINE
ON_CMD_LINE(argc, argv);
#else
if (argc >= 2) {
lcd_w = tk_atoi(argv[1]);
}
if (argc >= 3) {
lcd_h = tk_atoi(argv[2]);
}
#endif /*ON_CMD_LINE*/
tk_init(lcd_w, lcd_h, APP_TYPE, APP_NAME, APP_RES_ROOT);
#endif
#ifdef ASSETS_ZIP
assets_manager_set_loader(assets_manager(), asset_loader_zip_create(ASSETS_ZIP));
#endif /*ASSETS_ZIP*/
#if defined(WITH_LCD_PORTRAIT)
if (lcd_w > lcd_h) {
tk_set_lcd_orientation(LCD_ORIENTATION_90);
}
#endif /*WITH_LCD_PORTRAIT*/
#ifdef WITH_LCD_LANDSCAPE
if (lcd_w < lcd_h) {
tk_set_lcd_orientation(LCD_ORIENTATION_90);
}
#endif /*WITH_LCD_PORTRAIT*/
#ifdef WITH_FS_RES
system_info_set_default_font(system_info(), "default_full");
#endif /*WITH_FS_RES*/
assets_init();
#ifndef WITHOUT_EXT_WIDGETS
tk_ext_widgets_init();
#endif/*WITHOUT_EXT_WIDGETS*/
log_set_log_level(LOG_LEVEL_INFO);
log_info("Build at: %s %s\n", __DATE__, __TIME__);
#ifdef ENABLE_CURSOR
window_manager_set_cursor(window_manager(), "cursor");
#endif /*ENABLE_CURSOR*/
GLOBAL_INIT();
application_init();
tk_run();
application_exit();
GLOBAL_EXIT();
#ifdef WIN32
str_reset(&str);
#endif /*WIN32*/
#ifdef HAS_STDIO
fflush(stdout);
#endif /*HAS_STDIO*/
return 0;
}
我们把代码整理一下,单独看入口函数
#ifdef USE_GUI_MAIN
int gui_app_start(int lcd_w, int lcd_h) {
#elif defined(MOBILE_APP) && defined(WITH_SDL)
int SDL_main(int argc, char* argv[]) {
#elif defined(WIN32)
int WINAPI wWinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPWSTR lpcmdline, int ncmdshow) {
#else
int main(int argc, char* argv[]) {
这下看的就比较明晰了,gui_app_start()是用于无操作系统的裸机程序,SDL_main()用于手机APP,wWinMain()用于win32程序,main()用于控制台程序。在这些条件编译里面,成立的显然是#elif defined(WIN32),但为何提示找不到入口函数呢?难道是编译器不认识wWinMain()函数?嗯。。。还真的是,wWinMain()函数是WinMain()宽字符版,下面引用https://www.cnblogs.com/Dageking/archive/2014/01/15/3520406.html的一段描述
在Windows环境中,编译器的翻译策略是GB2312到UCS-2BE;Linux环境中的策略是UTF-8到UTF-32BE。
这时候就要求源文件的编码与编译器的本地化策略集中代码翻译的策略一致,例如VC只能读取GB2312的源代码(这里还是例外,VC太自作聪明了 ,会将很多其他代码在编译时自动转换成GB2312),而gcc只能读取UTF-8的源代码(这里就有个尴尬,MinGW运行win32下,所以只有 GB2312系统才认;而MinGW却用gcc编写,所以自己只认UTF-8,所以结果就是,MinGW的宽字符被废掉了)。
看来是MinGW在windows下不支持宽字符,那我们还是用WinMain()好了。打开C:\AWTK\SDK\awtk\src\awtk_main.inc,将wWinMain()函数修改为
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) {
问题顺利解决,再次编译,生成了一堆demo程序,运行一个看看
不过,还是有新问题
gcc -o bin\preview_ui.exe demos\preview_ui.o -Llib -lassets -lawtk -lextwidgets
-lwidgets -lbase -lgpinyin -lminiz -ltkc -llinebreak -lnanovg-agge -lnanovg -lag
ge -lSDL2 -lglad -lkernel32 -lgdi32 -luser32 -lwinmm -limm32 -lversion -lshell32
-lole32 -lOleaut32 -lAdvapi32 -loleaut32 -luuid -lstdc++ -lws2_32
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: c:/mingw/b
in/../lib/gcc/mingw32/8.2.0/../../../libmingw32.a(main.o):(.text.startup+0xb0):
undefined reference to `WinMain@16'
collect2.exe: error: ld returned 1 exit status
scons: *** [bin\preview_ui.exe] Error 1
scons: building terminated because of errors.
说是新问题,其实老问题,哈哈。修改原理同上。
5、直到看到这一句
才真正表明编译完全通过。
让人感到不解的是,有两个编译出来的程序竟然被卡巴斯基杀掉了,晕。。。
6、后记
为了加快编译速度,可以使用多线程编译,在scons后加参数-jx,x代表线程数,在使用多线程编译前需要安装pywin32。
pip install pywin32
7、后记的后记
这篇文章还没写完,ZLG官方已修复上述问题(我反馈的),但是必须到github更新最新源码,AWTK-Designer-x64-0.1.3-Preview-Setup安装包自带的SDK(1.3版)还是存在以上问题。