[心得] 用 c++ 来开发 uefi 程式

楼主: descent (“雄辩是银,沉默是金”)   2016-06-25 22:31:44
edk2 并没有支援用 c++ 来开发 uefi 程式, 真是不敢相信还有这么原始的开发环境,
竟然不支援 c++。我可是 c++ 爱好者, 不能用自己喜欢的语言开发程式, 感觉很不爽。
c++ 的好处我说过好几次了 (疑! 我根本没说过!!), c 我也是可以写的, 为什么坚持用
c++ 呢? 还真的说不上原因, 大概是网络上很多的讨论都对 c++ 很不好, 什么 XX 比不
上 C, YY 比不上 JAVA, 这些言论更让我对 c++ 抱不平, 决定要多多推广 c++, 我又不
善嘴炮言词, 只好用程式码来证明 c++ 的能耐。
《UEFI原理与程 ( http://goo.gl/GaujHw )》第十章说明如何用 c++ (g++) 来开发
uefi 程式并提供了 GcppPkg 这个范例, 不过很可惜, 这部份书上写的不够详细, 我花费
了不少时间还是搞不定怎么使用这个范例。
最后我做了和 GcppPkg 类似的事情, 再加上《UEFI原理与程 ( http://goo.gl/GaujHw )
》第十章的说明, 搞出了自己的 c++ 作法。所以我虽然没搞定书上的 GcppPkg 范例, 但
是书中内容还是帮了我不少。
最困难的是编译环境, 花了不少时间我才搞定 (没有搞懂, 是搞定), 找了
edk2/AppPkg/Applications/Main/Main.c 来修改, 这是使用 c 语言 main 的开发方式。
我建立了 edk2/AppPkg/Applications/Main/m.cpp (从
edk2/AppPkg/Applications/Main/Main.c 复制而来), 也复制了一份 m.inf, m.inf 最重
要的是 L27 ~ 42, 把 source code 的档案填进去, build 就会去编译这些档案。
m.inf
1 ## @file
2 # A simple, basic, application showing how the Hello application could be
3 # built using the "Standard C Libraries" from StdLib.
4 #
5 # Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the
BSD License
8 # which accompanies this distribution. The full text of the license may
be found at
9 # http://opensource.org/licenses/bsd-license.
10 #
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED.
13 ##
14
15 [Defines]
16 INF_VERSION = 0x00010006
17 BASE_NAME = m
18 FILE_GUID = 5ea97c46-7491-4dfd-b442-747010f3ce5f
19 MODULE_TYPE = UEFI_APPLICATION
20 VERSION_STRING = 0.1
21 ENTRY_POINT = ShellCEntryLib
22
23 #
24 # VALID_ARCHITECTURES = IA32 X64
25 #
26
27 [Sources]
28 m.cpp
29 bst.cpp
30 #crtbegin.cpp
31 eh.cpp
32 mylist.cpp
33 mymap.cpp
34 myvec.cpp
35 cstring.cpp
36 gdeque.cpp
37 k_stdio.cpp
38 mem.cpp
39 myiostream.cpp
40 mystring.cpp
41 #my_setjmp.c
42 my_setjmp.S
43
46 [Packages]
47 StdLib/StdLib.dec
48 MdePkg/MdePkg.dec
49 ShellPkg/ShellPkg.dec
50
51 [LibraryClasses]
52 LibC
53 LibStdio
54
55 [BuildOptions]
56 #GCC:*_*_X64_CC_FLAGS = -fno-exceptions -fno-rtti -ffreestanding
-nostdlib -nodefaultlibs -std=c++11
57 MSFT:*_*_*_CC_FLAGS =
58
再来是把这个 m.inf 加到 AppPkg.dsc。
AppPkg.dsc.diff
1 [LibraryClasses]
3 #
4 # Entry Point Libraries
5 #
6 @@ -105,6 +106,7 @@
7 ########################################################################
8
9 [Components]
10 AppPkg/Applications/Main/m.inf
以下是测试的 c++ 档案。cout 和 vector 不是 edk2 提供的, 是移植我那个玩具标准
c++ 程式库 ( http://goo.gl/xKIag7 )得来的, namespace 是 DS 而不是 std, 书上的
范例是移植 stl 过来, 我既然已经有自己的版本, 玩具归玩具, 没道理不用的。
还顺便测试一下目前最潮的 lambda 语法。
还有 setjmp/longjmp x64 的版本。
m.cpp
1 #include "myvec.h"
2 #include "myiostream.h"
3 #include "my_setjmp.h"
4 using namespace DS;
5
6 class Obj
7 {
8 public:
9 Obj()
10 {
11 i=10;
12 ::printf("ctor\n");
13 }
14 ~Obj()
15 {
16 ::printf("dtor\n");
17 }
18 private:
19 int i;
20 };
21
22 jmp_buf jbuf;
23
24 int lambda_test(int girls = 3, int boys = 4)
25 {
26 auto totalChild = [](int x, int y) ->int{return x+y;};
27 return totalChild(girls, boys);
28 }
29
30 int main (IN int Argc, IN char **Argv)
31 {
32 Obj obj;
33
34 int total = lambda_test();
35 cout << "total: " << total << endl;
36
37 vector<int> vec_i;
38
39 vec_i.push_back(1);
40 vec_i.push_back(2);
41 vec_i.push_back(3);
42 for (int i=0 ; i < vec_i.size() ; ++i)
43 cout << vec_i[i] << endl;
44
45 char *area = (char*)mymalloc(20);
46 char *a1 = new char [20];
47
48 int j_ret = 9;
49 //printf("aaa\n");
50 //getchar();
51 j_ret = my_setjmp(jbuf);
52
53 if (j_ret == 0)
54 {
55 printf("00\n");
56 }
57 else
58 {
59 printf("11\n");
60 return 0;
61 }
62
63 my_longjmp(jbuf, 5);
64 return 0;
65 }
build -p AppPkg/AppPkg.dsc 就可以编译出 m.efi 了, 不过先别急着打这个指令, 还要
写个 script gcc (书上提供了一个, 照抄后再加上 g++ option, ref list 1), 判断是
.c 档时出动 gcc, .cpp 档时出动 g++。当然也可能要修改
uefi/edk2/BaseTools/Scripts/GccBase.lds, 不过目前就不要搞太复杂, 这样就可以了

list 1. gcc script
1 #!/bin/sh
3 iscpp=0
4 for i in "$@" ; do
5 if [ "-" != "${i:0:1}" ] ; then
6 if [ "cpp" = "${i##*.}" ]; then
7 iscpp=1
8 fi
9 fi
10 done
11
12 if [ $iscpp = 0 ]; then
13 echo gcc
14 /usr/bin/gcc -DUEFI $@
15 else
16 echo g++
18 /usr/bin/g++ -DUEFI -fpermissive -I. -DSTM32 -fno-exceptions -fno-rtti
-ffreestanding -nostdlib -nodefaultlibs -std=c++11 $@
19 fi
好了, 现在可以痛快的敲下 build -p AppPkg/AppPkg.dsc
fig 2 为测试画面, ctor/dtor 正常发动了, lambda 也正常, DS::vector, DS::cout 也
正常, 感谢 bjarne stroustrup; 感谢 c++。
( https://goo.gl/NRsdfJ )
fig 2模拟器测试画面
为了保险起见, 我在真实机器上同样也做了测试, 真的是可以跑的。
( https://goo.gl/01E06B )
真实机器的 uefi 执行画面
global object ctor/dtor 没有搞定, 比我想的还复杂些, 这不是什么问题, 不要用就好
了。 XD
我是用手动呼叫 GLOBAL_XX function 来搞定这件事。
uefi-shceme 就是这么做的。
uefi function 手册:
http://www.bluestop.org/edk2/docs/trunk/getchar_8c.html (
http://goo.gl/MsOT9J )
// 本文使用 Blog2BBS 自动将Blog文章转成缩址的BBS纯文字 http://goo.gl/TZ4E17 //
blog 版本:
http://descent-incoming.blogspot.tw/2016/03/c-uefiedk2-0.html
作者: ferocious   2016-06-25 23:32:00
cool
作者: justassassin (DK01)   2016-06-26 15:28:00
我有在AMI待一阵子,据我所了解C的内存效能还真比较快一点,另外很大原因是因为历史包袱.
作者: Ethical (游志杰)   2016-06-27 11:31:00
有趣,推
作者: whitglint   2016-06-28 07:57:00
对 C++ 这么有爱一定要推!
作者: besmartAE (*无敌海滩男孩*)   2016-06-29 13:04:00
推 加入UEFI大军以后, 只写C 就忘记如何写C++了 XDDD
作者: saxontai (黑暗,点缀孤零零的星)   2016-06-30 23:37:00
有爱是一回事,不支援你爱的语言就说人家原始实在很奇怪
作者: ahwater01 (臭酸咖)   2016-07-01 11:40:00
我待的vendor,有C++写的module阿,比较少而已
作者: Ommm5566 (56天團)   2016-07-01 17:12:00
→ saxontai: 有爱是一回事,不支援你爱的语言就说人家

Links booklink

Contact Us: admin [ a t ] ucptt.com