下载源码和尝试性安装
项目开发需要,使用 Goahead 作为嵌入式 WEB 服务器。以前一直选择 Goahead,这一次也不例外。到 Goahead 主页一看,只有 GoAhead 5.2.0 呈现出来。好吧,那就下载下来看看,这 5.2.0 和以前的版本在使用上到底有啥不同的地方呢?
下载主页:Download GoAhead | GoAhead Embedded Web Server | Embedded Web Servers | Embedthis Software
下载很方便,也很快捷。我是从ubuntu 18.04的桌面直接使用 Firefox 下载的,5.8MB的源码不到十秒钟就下载下来了,然后给它解压到我的工作目录。先不做任何修改,在 x86_64 平台上直接编译一遍,看编译过程怎么样,令人欣慰的是 make 和 sudo make install 没有一处错误或警告,执行完 make install 之后,在 /etc/goahead 文件夹中已经拷贝好了 auth.txt, route.txt, self.crt和 self.key 四个文件。输入 goahead -v --home /etc/goahead /var/www (事先将网页文件拷贝到了 /var/www 中了),从 Firefox 输入 127.0.0.1 直接显示出 index.html,这是一路无坑。
使用 LicheePI 的交叉编译链进行编译
在本机上编译安装后,心里有了点底。下一步使用 LicheePI 的交叉编译链 linaro-arm-linux-gnueabihf 进行编译看看。在编译之前,还是从 Makefile 开始。Goahead 5.2.0 的 Makefile 和以前版本看不出什么区别,于是转而查看 projects 目录下的几组 mk 文件。
我用的是ubuntu 18.04,打开 <你的工作目录>/goahead-5.2.0/projects/goahead-linux-default.mk 文件,找到对 CC 和 AR 的定义,可以看到如下的片段。
#
# goahead-linux-default.mk -- Makefile to build Embedthis GoAhead for linux
#
NAME := goahead
VERSION := 5.2.0
PROFILE ?= default
ARCH ?= $(shell uname -m | sed 's/i.86/x86/;s/x86_64/x64/;s/arm.*/arm/;s/mips.*/mips/')
CC_ARCH ?= $(shell echo $(ARCH) | sed 's/x86/i686/;s/x64/x86_64/')
OS ?= linux
CC ?= gcc
AR ?= ar
CONFIG ?= $(OS)-$(ARCH)-$(PROFILE)
BUILD ?= build/$(CONFIG)
LBIN ?= $(BUILD)/bin
PATH := $(LBIN):$(PATH)
ME_COM_COMPILER ?= 1
ME_COM_LIB ?= 1
ME_COM_MATRIXSSL ?= 0
ME_COM_MBEDTLS ?= 1
ME_COM_NANOSSL ?= 0
ME_COM_OPENSSL ?= 0
ME_COM_OSDEP ?= 1
ME_COM_SSL ?= 1
ME_COM_VXWORKS ?= 0
ME_COM_OPENSSL_PATH ?= "/path/to/openssl"
ifeq ($(ME_COM_LIB),1)
ME_COM_COMPILER := 1
endif
ifeq ($(ME_COM_MBEDTLS),1)
ME_COM_SSL := 1
endif
ifeq ($(ME_COM_OPENSSL),1)
ME_COM_SSL := 1
endif
当 CC 未赋值时默认值被定义为 gcc,AR 默认值是 ar,搜索了一下全文,只有这两个编译/打包程序。于是采用了如下命令对 Goahead 进行编译。
Bingo!居然没有任何错误和警告提示就成功了!
命令:
CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar make -j16
运行结果:
/home/luoyuan/Documents/gwdev/engine/../goahead-5.2.0/build/linux-x64-default/bin
make[1]: Entering directory '/home/luoyuan/Documents/gwdev/goahead-5.2.0'
make[1]: Leaving directory '/home/luoyuan/Documents/gwdev/goahead-5.2.0'
make[1]: Entering directory '/home/luoyuan/Documents/gwdev/goahead-5.2.0'
make --no-print-directory -f projects/goahead-linux-default.mk all
[Info] Use make SHOW=1 to trace executed commands.
[Compile] build/linux-x64-default/obj/mbedtls.o
[Compile] build/linux-x64-default/obj/goahead-mbedtls.o
[Compile] build/linux-x64-default/obj/action.o
[Compile] build/linux-x64-default/obj/alloc.o
[Compile] build/linux-x64-default/obj/auth.o
[Compile] build/linux-x64-default/obj/cgi.o
[Compile] build/linux-x64-default/obj/http.o
[Compile] build/linux-x64-default/obj/fs.o
[Compile] build/linux-x64-default/obj/jst.o
[Compile] build/linux-x64-default/obj/file.o
[Compile] build/linux-x64-default/obj/crypt.o
[Compile] build/linux-x64-default/obj/osdep.o
[Compile] build/linux-x64-default/obj/options.o
[Compile] build/linux-x64-default/obj/rom.o
[Compile] build/linux-x64-default/obj/js.o
[Compile] build/linux-x64-default/obj/route.o
[Compile] build/linux-x64-default/obj/runtime.o
[Compile] build/linux-x64-default/obj/socket.o
[Compile] build/linux-x64-default/obj/time.o
[Compile] build/linux-x64-default/obj/upload.o
[Compile] build/linux-x64-default/obj/mn-web.o
[Copy] build/linux-x64-default/bin
[Compile] build/linux-x64-default/obj/goahead.o
[Link] build/linux-x64-default/bin/libmbedtls.a
[Link] build/linux-x64-default/bin/libgoahead-mbedtls.a
[Link] build/linux-x64-default/bin/libgo.so
[Link] build/linux-x64-default/bin/goahead
On Linux/MacOS, you can now install via "sudo make w -j --jobserver-fds=3,4 install" or run GoAhead via: "sudo make run"
To run locally, put linux-x64-default/bin in your path
找到build/linux-x64-default/bin,看到经过 arm-linux-gnueabihf-strip 后文件列表如下。
luoyuan@iotdev:~/Documents/gwdev/goahead-5.2.0/build/linux-x64-default/bin$ dir
total 2540
drwxrwxr-x 2 luoyuan luoyuan 4096 Sep 14 20:13 ./
drwxrwxr-x 5 luoyuan luoyuan 4096 Sep 14 20:13 ../
-rw-rw-r-- 1 luoyuan luoyuan 116 Sep 13 18:41 auth.txt
-rw-r--r-- 1 luoyuan luoyuan 1724 Sep 14 20:13 ca.crt
-rw-r--r-- 1 luoyuan luoyuan 1675 Sep 14 20:13 ca.key
-rw-r--r-- 1 luoyuan luoyuan 924 Sep 14 20:13 ec.crt
-rw-r--r-- 1 luoyuan luoyuan 302 Sep 14 20:13 ec.key
-rwxrwxr-x 1 luoyuan luoyuan 28404 Sep 14 20:13 goahead*
-rw-rw-r-- 1 luoyuan luoyuan 53838 Sep 14 20:13 libgoahead-mbedtls.a
-rwxrwxr-x 1 luoyuan luoyuan 1270468 Sep 14 20:13 libgo.so*
-rw-rw-r-- 1 luoyuan luoyuan 937736 Sep 14 20:13 libmbedtls.a
-rw-r--r-- 1 luoyuan luoyuan 256338 Sep 14 20:13 roots.crt
-rw-r--r-- 1 luoyuan luoyuan 1444 Sep 14 20:13 self.crt
-rw-r--r-- 1 luoyuan luoyuan 1679 Sep 14 20:13 self.key
-rw-r--r-- 1 luoyuan luoyuan 1444 Sep 14 20:13 test.crt
-rw-r--r-- 1 luoyuan luoyuan 1679 Sep 14 20:13 test.key
goahead 的可执行文件为28404 字节,比以前版本的要大一点。libgo.so 是1.21MB,和以前版本的差不多。OK!把 goahead 和 libgo.so 这两个文件分别拷贝到目标板的 /usr/bin/ 目录和 /usr/lib/ 目录下,把 auth.txt,self.crt,self.key,和 src 目录下的默认 route.txt 拷贝到目标板的 /etc/goahead 目录下,网页文件拷贝到目标板的 /var/www 目录下,然后在 LicheePI 上执行
# goahead -v --home /etc/goahead /var/www
在 Firefox 的地址栏中输入目标板的 IP 地址:http://192.168.0.201,然后回车,Bingo!网页正确显示。
从这个过程看,Goahead 5.2.0 真心是修改了以前版本的一些毛病,例如按照上述过程编译的 Goahead 4.1.3/4.1.0/3.6.5,在初次运行时都会报无法获取本机IP地址的错误,还要去修改 http.c 的文件,在 setLocalHost 函数中将 IP 地址硬性赋值。
Goahead 5.2.0 的另一个改进是默认支持多线程 Make。
在Goahead 5.2.0 代码中增加自定义功能
和以往版本相似,在Goahead 5.2.0中增加自定义功能(jst,action,http API响应等)的通用步骤如下。
编制头文件 web-ext.h
在goahead-5.2.0/src 目录下建立一个web-ext.h的头文件,将新增功能所需的函数在这个头文件中进行预定义 ,顺便还可以 #define 你所需要的常量和结构。为了能使用 goahead API,在 web-ext.h 中要 #include "goahead.h",还可以 #include 其它你要用得到的头文件,例如 pthread.h,cJSON.h 等,代码示例如下片段。
/**
* @brief web-ext header file
* @file ...app/goahead-5.2.0/src/web-ext.h
* @version V1.0.0
* @date
* @author
* @copyright Copyright(c) 2020-2022
* @remark
*/
#ifndef _WEB_EXT_H_GOA_5_2_0_
#define _WEB_EXT_H_GOA_5_2_0_
/* Your user-defined defines */
#ifndef MY_APP_ERROR_CODE
#define MY_APP_ERROR_OK 0
#define MY_APP_ERROR_EXPIRE 100
#define MY_APP_ERROR_IGNORE 200
#define MY_APP_ERROR_FAIL 900
#define MY_APP_ERROR_PAR_MIS 910
#define MY_APP_ERROR_PAR_BAD 950
#endif
#define WEB_REBOOT_STACK_SIZE 65536
#define _DBG_B0_ 1
#define _DBG_B1_ 1
/* Global includes */
#include "goahead.h"
#include <pthread.h>
// Commonly used string utilities
void my_string_trim(unsigned char *s);
static void ajaxResponse(Webs *wp, char *msg);
static void ajaxReject(Webs *wp, char *msg);
// --------------------------------------------------------
// ASP actions for my_app
// --------------------------------------------------------
/**
* @brief Web Server jst/actions-C functions co-relation
*
* @return int, always 0
*/
int myAppWebServiceSetup();
int myAppWebServiceDestroy();
static void myAppError(char *rsp, int ec, char *em);
static void myActWeb_Login(Webs *wp);
static void myActGateway_GetParameters(Webs *wp);
static void myActGateway_GetIpSettings(Webs *wp);
static void myActGateway_SaveIpSettings(Webs *wp);
/**
* @brief Reboot gateway thread
* @param [in] argv: void*, nothing here
*/
static void *gw_reboot_thread(void *argv);
/**
* @brief Get gateway basic parameters
*
* @param [out] ret_json: Gateway parameters in JSON string
* @return 0 if success; !0 for error. See MY_APP_ERROR_CODE #defines
*/
static int ws_gateway_getparameters(char *ret_json);
/**
* @brief Get gateway IP settings
*
* @param [out] ret_json: Gateway IP settings in JSON string
* @return 0 if success; !0 for error. See MY_APP_ERROR_CODE #defines
*/
static int ws_gateway_getipsettings(char *ret_json);
/**
* @brief Save IP(v4) settings to gateway
*
* @param [in] ipmode: 1 for Static; 2 for DHCP
* @param [in] ipaddr: IPv4 address set to gateway
* @param [in] subnetmask: Subnet mask of IP address
* @param [in] defaultgateway: Default gateway of the gateway
* @param [in] dnsprimary: IPv4 address of primary DNS server
* @param [in] dnssecondary: IPv4 address of secondary DNS server
* @return 0 if success; !0 for error. See MY_APP_ERROR_CODE #defines
*/
static int ws_gateway_saveipsettings(const int ipmode,
const char *ipaddr,
const char *subnetmask,
const char *defaultgateway,
const char *dnsprimary,
const char *dnssecondary);
// ----------------- End of Extensions ----------------------------
#endif // _WEB_EXT_H_GOA_5_2_0_
编制 web-ext.c 文件,实现在 web-ext.h 中所定义的所有函数
这里只列出了 myAppWebServiceSetup() 函数的内容,其余的就略去详细内容了哈。。。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "web-ext.h"
int tvnMnWebServiceSetup()
{
// ---------------------------------------------------------------
// ASP Actions for Web extension
// ---------------------------------------------------------------
websDefineAction("aspWeb_Login", myActWeb_Login);
websDefineAction("aspGateway_GetGwParameters", myActGateway_GetParameters);
websDefineAction("aspGateway_GetIpSettings", myActGateway_GetIpSettings);
websDefineAction("aspGateway_GetToken", myActGateway_GetToken);
websDefineAction("aspGateway_SaveIpSettings", myActGateway_SaveIpSettings);
websDefineAction("aspGateway_UploadToken", mnyActGateway_UploadToken);
// --------------------- End of extension --------------------
}
修改 goahead.c 文件将web-ext.h #include 进来,并调用相应函数
直接上代码吧。
#if ME_UNIX_LIKE && !MACOSX
/*
Service events till terminated
*/
if (websGetBackground())
{
if (daemon(0, 0) < 0)
{
error("Cannot run as daemon");
return -1;
}
}
#endif
/* 揍是介个 */
myWebServiceSetup();
websServiceEvents(&finished); /* 找到这条指令 ! */
logmsg(1, "Instructed to exit");
websClose();
/* 还有介个 */
myWebServiceDestroy();
#if WINDOWS
windowsClose();
#endif
return 0;
}
将 web-ext.o 链接到 goahead 的编译链条中
- 修改 .../goahead-5.2.0/projects/goahead-linux-default.mk 文件,把 web-ext 链接进编译链条中。需要做如下的修改:3.1 找到 clean: 段(大概在第110行上下),将 web-ext.o 加入到删除列表中
clean:
rm -f "$(BUILD)/obj/action.o"
rm -f "$(BUILD)/obj/alloc.o"
rm -f "$(BUILD)/obj/auth.o"
rm -f "$(BUILD)/obj/cgi.o"
rm -f "$(BUILD)/obj/cgitest.o"
rm -f "$(BUILD)/obj/crypt.o"
rm -f "$(BUILD)/obj/file.o"
rm -f "$(BUILD)/obj/fs.o"
rm -f "$(BUILD)/obj/goahead-mbedtls.o"
......
......
......
rm -rf "$(BUILD)/obj/web-ext.o"
......
......
rm -f "$(BUILD)/bin/libgo.so"
rm -f "$(BUILD)/bin/libgoahead-mbedtls.a"
rm -f "$(BUILD)/bin/libmbedtls.a"
clobber: clean
rm -fr ./$(BUILD)
- 在 goahead-linux-default.mk 的最后,加上如下 Make 命令
#
# web-ext.o
# 99
#
DEPS_99 += $(BUILD)/inc/goahead.h
DEPS_99 += $(BUILD)/inc/js.h
$(BUILD)/obj/web-ext.o: src/web-ext.c $(DEPS_99)
@echo ' [Compile] $(BUILD)/obj/web-ext.o'
mkdir -p "$(BUILD)/inc"
@cp src/web-ext.h $(BUILD)/inc/web-ext.h
@touch $(BUILD)/inc/web-ext.h
$(CC) -c -o $(BUILD)/obj/web-ext.o $(CFLAGS) $(DFLAGS) \
-D_FILE_OFFSET_BITS=64 \
-D_FILE_OFFSET_BITS=64 \
-DMBEDTLS_USER_CONFIG_FILE=\"embedtls.h\" \
-DME_COM_OPENSSL_PATH=$(ME_COM_OPENSSL_PATH) \
$(IFLAGS) "-I$(ME_COM_OPENSSL_PATH)/include" \
src/web-ext.c
- 找到第530行上下,将 web-ext.o 加入到 DEPS_40 (libgo要用到的)的最后,如下所示
#
# libgo
#
DEPS_40 += $(BUILD)/inc/osdep.h
ifeq ($(ME_COM_MBEDTLS),1)
DEPS_40 += $(BUILD)/bin/libgoahead-mbedtls.a
endif
ifeq ($(ME_COM_OPENSSL),1)
DEPS_40 += $(BUILD)/bin/libgoahead-openssl.a
endif
DEPS_40 += $(BUILD)/inc/goahead.h
DEPS_40 += $(BUILD)/inc/js.h
DEPS_40 += $(BUILD)/obj/action.o
......
......
......
DEPS_40 += $(BUILD)/obj/time.o
DEPS_40 += $(BUILD)/obj/upload.o
# 下一条将 web-ext.o 加入到 libgo 的编译链条中
DEPS_40 += $(BUILD)/obj/web-ext.o
- 最后,找到第590行上下,在 $(BUILD)/bin/libgo.so: $(DEPS_40) 这一段中,按照如下修改,将 web-ext.o 加进去。注意这一段的第一行末尾加上了 $(DEPS_99),就是第2步新建的一个 DEPS 段;还有就是在所有 .o 的最后加上 web-ext.o
$(BUILD)/bin/libgo.so: $(DEPS_40) $(DEPS_99)
@echo ' [Link] $(BUILD)/bin/libgo.so'
$(CC) -shared -o $(BUILD)/bin/libgo.so $(LDFLAGS) $(LIBPATHS) \
"$(BUILD)/obj/action.o" \
"$(BUILD)/obj/alloc.o" \
"$(BUILD)/obj/auth.o" \
"$(BUILD)/obj/cgi.o" \
"$(BUILD)/obj/crypt.o" \
"$(BUILD)/obj/file.o" \
"$(BUILD)/obj/fs.o" \
"$(BUILD)/obj/http.o" \
"$(BUILD)/obj/js.o" \
"$(BUILD)/obj/jst.o" \
"$(BUILD)/obj/options.o" \
"$(BUILD)/obj/osdep.o" \
"$(BUILD)/obj/rom.o" \
"$(BUILD)/obj/route.o" \
"$(BUILD)/obj/runtime.o" \
"$(BUILD)/obj/socket.o" \
"$(BUILD)/obj/time.o" \
"$(BUILD)/obj/upload.o" \
"$(BUILD)/obj/web-ext.o" \
$(LIBPATHS_40) $(LIBS_40) $(LIBS_40) $(LIBS)
上面的步骤做完后,执行
CC=arm-linux-gnueabihf-gcc AR=arm-linux-gnueabihf-ar make -j16
指令即可将 web-ext.h/web-ext.c 中的函数功能加入到 libgo.so 中。
上述步骤,亲测可用,供学习交流。