[心得] 用 c++ 來開發 uefi 程式

看板C_and_CPP作者 (「雄辯是銀,沉默是金」)時間8年前 (2016/06/25 22:31), 8年前編輯推噓7(703)
留言10則, 9人參與, 最新討論串1/1
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 -- 紙上得來終覺淺,絕知此事要躬行。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.150.253.245 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1466865113.A.642.html

06/25 23:29, , 1F
06/25 23:29, 1F

06/25 23:32, , 2F
cool
06/25 23:32, 2F

06/26 15:28, , 3F
我有在AMI待一陣子,據我所了解C的記憶體效能還真
06/26 15:28, 3F

06/26 15:29, , 4F
比較快一點,另外很大原因是因為歷史包袱.
06/26 15:29, 4F
感謝說明

06/27 11:31, , 5F
有趣,推
06/27 11:31, 5F
※ 編輯: descent (118.150.253.245), 06/27/2016 14:03:11

06/28 07:57, , 6F
對 C++ 這麼有愛一定要推!
06/28 07:57, 6F

06/29 13:04, , 7F
推 加入UEFI大軍以後, 只寫C 就忘記如何寫C++了 XDDD
06/29 13:04, 7F

06/30 23:37, , 8F
有愛是一回事,不支援你愛的語言就說人家原始實在很奇怪
06/30 23:37, 8F

07/01 11:40, , 9F
我待的vendor,有C++寫的module阿,比較少而已
07/01 11:40, 9F

07/01 17:12, , 10F
→ saxontai: 有愛是一回事,不支援你愛的語言就說人家
07/01 17:12, 10F
文章代碼(AID): #1NRfNPP2 (C_and_CPP)