您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么編寫C++程序并把它做成ipk包”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么編寫C++程序并把它做成ipk包”吧!
在 SDK/package/ 路徑下創(chuàng)建 cpp-demo 目錄,并生成一個非常簡單的 cpp 程序
$ cd SDK $ mkdir -p package/cpp-demo $ cd package/cpp-demo $ touch Makefile $ mkdir src $ cd src $ touch Makefile main.cpp
形成如下目錄結(jié)構(gòu):
$ tree package/demo-cpp package/cpp-demo/ |-- Makefile `-- src |-- main.cpp `-- Makefile
package/cpp-demo/src/main.cpp內(nèi)容:
#include <iostream> using namespace std; int main(int argc, char **argv) { cout << "This is C++ Demo" << endl; return 0; }
package/cpp-demo/src/Makefile內(nèi)容:
target=cpp-demo ALL:$(target) objects=main.o cpp-demo: $(objects) $(CXX) -o $(target) $(objects) clean: @rm -rf $(objects)
注意:上面用的是CXX,而不是CC,就這點區(qū)別。
package/Makefile內(nèi)容:
include $(TOPDIR)/rules.mk PKG_NAME:=cpp-demo PKG_RELEASE:=1 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk define Package/cpp-demo SECTION:=utils CATEGORY:=Utilties TITLE:=cpp-demo endef define Build/Prepare $(MKDIR) -p $(PKG_BUILD_DIR) $(CP) ./src/* $(PKG_BUILD_DIR) endef define Package/cpp-demo/install $(INSTALL_DIR) $(1)/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/cpp-demo $(1)/bin endef $(eval $(call BuildPackage,cpp-demo))
在SDK目錄下 make V=s,結(jié)果報錯:
Package cpp-demo is missing dependencies for the following libraries: libstdc++.so.6
說是要依賴 libstdc++.so.6 這個庫文件?
那好吧,在本地機上安裝一個便是了。
$ sudo yum install libstdc++ ...省略... Package libstdc++-4.4.7-11.el6.i686 already installed and latest version Nothing to do
說明本地已安排了libstdc++了的。難不成是版本對不上號?
我用 locate命令找了一下 libstdc++這個文件,發(fā)現(xiàn)存在 /usr/lib/libstdc++.so.6 文件。這應(yīng)該就是上面需要的庫吧。
應(yīng)該在LD_LIBRARY_PATH環(huán)境變量中沒有將 /usr/lib 加入到其中。如下:
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib make V=s
這次,報:
Package cpp-demo is missing dependencies for the following libraries: libc.so.6 libm.so.6 libstdc++.so.6
不湊效?!
不過靜下心來想想,我編譯cpp-demo需要的是開發(fā)機的動態(tài)庫呢,還是目標(biāo)機的動態(tài)庫?
動態(tài)庫是程序在運行起來后加載的庫,那么cpp-demo在目標(biāo)機上運行起來后,加載的動態(tài)庫應(yīng)該是目標(biāo)機的,不應(yīng)該是開發(fā)機的。所以,剛剛我在整開發(fā)機上的動態(tài)庫,與這個應(yīng)該是兩碼事兒。
在SDK路徑下搜所有的動態(tài)庫文件:
$ find -name lib*.so.* ./staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libzmq.so.4 ./staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libevent_openssl-2.0.so.5 ./staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libpopt.so.0.0.0 ...<略> ./staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/mysql/libmysqlclient.so.16 ./staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/mysql/libmysqlclient_r.so.16.0.0 ...<略> ./staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/lib/libc.so.0 ./staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/lib/libstdc++.so.6 ...<略> ./staging_dir/host/lib/libltdl.so.7 ./staging_dir/host/lib/liblzma.so.5
有很多,也看到了 libstdc++.so.6
應(yīng)該是在鏈接時將 libstdc++.so.6 所在的路徑加進來吧。就像:
g++ -L./staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/lib/ -lstdc++
這樣。
我們檢查編譯調(diào)試信息打印出來的LDFLAGS的值:
LDFLAGS="-L/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib\ -L/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/target-mips_34kc_uClibc-0.9.33.2/lib\ -L/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/lib\ -L/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/lib "
這說明,libstdc++.so.6已在LDFLAGS的路徑范圍之下,編譯不應(yīng)該出錯。
還是好好研究一下錯誤提示:
make[4]: Entering directory `/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo' make[4]: Nothing to be done for `ALL'. make[4]: Leaving directory `/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo' touch /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/.built mkdir -p /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/bin/ar71xx/packages /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ipkg-ar71xx/cpp-demo/CONTROL /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/target-mips_34kc_uClibc-0.9.33.2/pkginfo install -d -m0755 /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ipkg-ar71xx/cpp-demo/bin install -m0755 /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/cpp-demo /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ipkg-ar71xx/cpp-demo/bin find /home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ipkg-ar71xx/cpp-demo -name 'CVS' -o -name '.svn' -o -name '.#*' -o -name '*~'| xargs -r rm -rf Package cpp-demo is missing dependencies for the following libraries: libc.so.6 libm.so.6 libstdc++.so.6 make[3]: *** [/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/bin/ar71xx/packages/base/cpp-demo_1_ar71xx.ipk] Error 1
從前3行看來,cpp-demo的編譯好像是正常通過了的。
查看 build_dir/target-mips
tree build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ |-- cpp-demo |-- ipkg-ar71xx | `-- cpp-demo | |-- bin | | `-- cpp-demo | `-- CONTROL |-- main.cpp |-- main.o `-- Makefile 4 directories, 5 files
在這個路徑下已經(jīng)成功生成了cpp-demo可執(zhí)行程序。證明,編譯是通過了的。
為什么 find 執(zhí)行完就報錯?
怎么入手?從錯誤提示入手吧,看看是在哪里提示"Package cpp-demo is missing dependencies for the following libraries"的。
在SDK目錄下執(zhí)行 grep 命令進行查找。
$ grep "is missing dependencies for the following libraries" ./* -R ./include/package-ipkg.mk: echo "Package $(1) is missing dependencies for the following libraries:" >&2; \
打開 include/package-ipkg.mk 文件看個究竟。
在74行輸入錯誤提示信息,條件是存在文件 $(PKG_INFO_DIR)/$(1).missing 這個文件。那問題來了,這個文件是怎么產(chǎn)生的呢?
行70~71行的意思是:如果在 $(PKG_INFO_DIR)/$(1).provides 中沒有找到$FILE的,就把$FILE寫入到 $(PKG_INFO_DIR)/$(1).missing
其中 $(1)值為cpp-demo,相應(yīng)的 cpp-demo.provides 與 cpp-demo.missing 都是在 SDK/staging_dir/target-mips_34kc_uClibc-0.9.33.2/pkginfo/ 路徑下的。
那么 xxx.provides 文件里的內(nèi)容代碼什么呢?
63~68行為一個執(zhí)行進程,它用管道與while語句連接起來。也就是說while里面的FILE變量就是63~68行標(biāo)準(zhǔn)輸出的結(jié)果。
65,66,67是在根據(jù)平臺設(shè)置環(huán)境變量的值,然后在68行執(zhí)行 SDK/scripts/gen-dependencies.sh。
我猜gen-dependencise.sh執(zhí)行輸出的一定是cpp-demo所依賴的庫名稱。
我們打開 SDK/scripts/gen-dependencise.sh 文件,其中最核心的一段:
#!/usr/bin/env bash TARGETS=$* XARGS="${XARGS:-xargs -r}" find $TARGETS -type f -a -exec file {} \; | \ sed -n -e 's/^\(.*\):.*ELF.*\(executable\|shared object\).*,.* stripped/\1/p' | \ $XARGS -n1 $READELF -d | \ awk '$2 ~ /NEEDED/ && $NF !~ /interpreter/ && $NF ~ /^\[?lib.*\.so/ { gsub(/[\[\]]/, "", $NF); print $NF }' | \ sort -u
從TARGETS目錄下查看到所有的文件。對每個文件并用file命令輸入該文件的基本信息。用sed對file的輸出進行分析,找出有"ELF"且有"executable"或"shared object"關(guān)鍵字的文件。
再對這個文件用 readelf -d 命令輸入ELF文件的信息,再用awk從中提取出所依賴的 *.so 文件名,并打印到標(biāo)準(zhǔn)輸出。
我親手用readelf查看一下cpp-demo依賴什么:
$ readelf -d build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/cpp-demo Dynamic section at offset 0x934 contains 23 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libstdc++.so.6] 0x00000001 (NEEDED) Shared library: [libm.so.6] 0x00000001 (NEEDED) Shared library: [libgcc_s.so.1] 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x0000000c (INIT) 0x80484e8 ...<省略>
它確實依賴 libstdc++.so.6, libm.so.6, libc.so.6 這3個動態(tài)庫文件。
現(xiàn)在 package-ipk.mk 文件中過程理清楚了。cpp-demo所依賴的庫文件,在cpp-demo.provides 文件中找不到就會寫入到 cpp-demo.missing。
如果純粹是想讓它打包成功的話,那就把差的文件寫入到cpp-demo.provides文件就了事兒了。
這樣做會不會有后有后遺癥?
試試再說~,結(jié)果還是不成功。原因是cpp-demo.provides是自動生成的。就算是我手動改了它,下次make的時候還是會還原的。
那新問題是:Who在生成這個cpp-demo.provides文件?它是根據(jù)什么生成這個文件的?
那就grep一下關(guān)鍵字"$(1).provides",應(yīng)該就可以找到。結(jié)果還是在 package-ipk.mk 文件里:
L185,將數(shù)據(jù)進行排序了之后寫入到 cpp-demo.provides。數(shù)據(jù)由L179~184產(chǎn)生。
L179,將IDIR_$(1)目錄下的所有 lib*.so*, *.ko 文件名打印出來,作為已有的庫文件,由L185寫入cpp-demo.provides文件。
IDIR_$(1)的定義如下:
L180~184這個for循環(huán)不太好理解。
其中patsubst,是個字串替換命令,其詳細用法見:[makefile中的patsubst]
$(patsubst %,$(PKG_INFO_DIR)/%.provides,$(IDEPEND_$(1))) 返回的結(jié)果是:將$(IDEPEND_$(1))中的每個結(jié)果 item,變成:$(PKG_INFO_DIR)/$(item).provides返回。
那IDEPEND_$(1)是什么?
博主深深地感到腦容量不夠了。有哪位高人知道的,請指點一下。
跳出這個洞,回到L180~184,的問題。它就是把其它的某個相關(guān)的 xxxx.provides 文件里的內(nèi)容輸出來。
博主通過經(jīng)驗推斷,xxxx.provides 代表的是是與cpp-demo依賴的組件所依賴的庫。
注意:L184,是 $(Package/$(1)/extra_provides)。也就是說,我們可以在 package/cpp-demo/Makefile 文件中定義 Package/cpp-demo/extra_provides 宏來強制性地將那幾個庫加進去。比如:
define Package/cpp-demo/extra_provides echo "libstdc++.so.6" echo "libc.so.6" echo "libm.so.6" endef
經(jīng)過試驗,正確的寫法如下:
define Package/cpp-demo/extra_provides echo 'libstdc++.so.6'; \ echo 'libm.so.6'; \ echo 'libc.so.6'; endef
這樣寫果然湊效,再 make V=s,能夠打包成功。
但是,有點我們必須明確的是:在打包中生成的ipk文件里,是沒有l(wèi)ibstdc++, libc, libm這3個庫的。如果所安裝的OpenWrt系統(tǒng)里也沒有這3個庫,那么我們安裝的應(yīng)用程序是不能正常使用的。
相當(dāng)于是在騙ipk工具,我們已具備了上面這3個庫文件。
比較穩(wěn)妥的方法是采用方案二,如下:
還有另一個方法,注意L176,$(call Package/$(1)/install, $$(IDIR_$(1))),這個就是引用了我們在Makefile里寫的 Package/cpp-demo/install 宏么?
我們可以在這個宏里,將它需要的幾個庫文件復(fù)制到 $(1) 對應(yīng)的目錄下。
如下修改:
define Package/cpp-demo/install $(INSTALL_DIR) $(1)/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/cpp-demo $(1)/bin $(INSTALL_DIR) $(1)/usr/lib $(INSTALL_DATA) $(TOOLCHAIN_DIR)/lib/libstdc++.so.6 $(1)/usr/lib $(INSTALL_DATA) $(TOOLCHAIN_DIR)/lib/libm.so $(1)/usr/lib/libm.so.6 $(INSTALL_DATA) $(TOOLCHAIN_DIR)/lib/libc.so $(1)/usr/lib/libc.so.6 endef
其中,INSTALL_DATA 與 TOOLCHAIN_DIR 這兩個變量在 rules.mk 文件中定義。
之所以選用 TOOLCHAIN_DIR,是因為libstdc++.so.6這個文件就在這個變量所對應(yīng)的路徑下。不信,你可以用 find 命令查找一下。
好了,這樣再make V=s,就能正常打包了。
這個方法不是我想到的,是[GunNRose]給我建議。修改 Makefile:
define Package/cpp-demo ...<略> DEPENDS:+=libstdcpp endef
經(jīng)博主親自嘗試,是OK的。
不過,為什么是叫l(wèi)ibstdcpp而不是libstdc++呢?這個有待研究一下。
官方Dependence文檔:http://wiki.openwrt.org/doc/devel/dependencies
將生成的 SDK/bin/ar71xx/packages/base/cpp-demo_1_ar71xx.ipk 文件用 scp 傳到目標(biāo)機上進行安裝試用。
$ scp bin/ar71xx/packages/base/cpp-demo_1_ar71xx.ipk root@192.168.1.2: root@192.168.1.2's password: cpp-demo_1_ar71xx.ipk 100% 278KB 278.0KB/s 00:01 $
然后用 SSH 登陸到目標(biāo)機上去安裝。
root@OpenWrt:~# opkg install cpp-demo_1_ar71xx.ipk Installing cpp-demo (1) to root... Configuring cpp-demo.
試執(zhí)行一下 cpp-demo
root@OpenWrt:~# cpp-demo /bin/cpp-demo: line 3: syntax error: unexpected word (expecting ")")
Oops~ 運行不起來。
檢查一下那3個依賴的庫文件,都還在。那為什么不能運行起來呢?
之前博主在排查上面庫依賴的問題的時候已看出了端倪。
在 SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ipkg-ar71xx/cpp-demo/ 路徑下的所有內(nèi)容都是直接打包的文件。而這里面的 bin/cpp-demo 可執(zhí)行文件在開發(fā)機上居然都正常運行。
這明顯不對,bin/cpp-demo 應(yīng)該是運行在目標(biāo)機上的ELF文件,怎么可以在開發(fā)機上運行?開發(fā)機與目標(biāo)機都不是同類型的CPU。一定是這里出了問題!
博主在想,是不是在交叉編譯的時候,選用了本機的gcc,而非目標(biāo)機的gcc。如下為 SDK/package/cpp-demo/src/Makefile :
target=cpp-demo ALL:$(target) objects=main.o cpp-demo: $(objects) echo "CXX = $(CXX)" $(CXX) -o $(target) $(objects) clean: @rm -rf $(objects)
為了知道CXX到底是哪一個編譯器。我特地加了 echo "CXX = $(CXX)">
把 SDK/build_dir 刪了重新 make。為了方便分析,
$ rm -rf build_dir $ make V=s | less
分析打印的信息:
CC="mips-openwrt-linux-uclibc-gcc" GCC="mips-openwrt-linux-uclibc-gcc" CXX="mips-openwrt-linux-uclibc-g++" ... make[4]: Entering directory `/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo' make[4]: Nothing to be done for `ALL'. make[4]: Leaving directory `/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo' ...
咦?Nothing to be done for 'ALL',表示沒有什么需要再編譯的了。
我趕緊查看
[SDK]$ ls build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo/ cpp-demo ipkg-ar71xx main.cpp main.o Makefile
發(fā)現(xiàn)cpp-demo已經(jīng)生成,而且在開發(fā)機上可運行。這個cpp-demo是怎么來的?難不出是從 package/cpp-demo/src里來的?
我突然想到,我之前進入 package/cpp-demo/src/ 路徑下,執(zhí)行過一次 make,那時一定生成了一個 cpp-demo 可執(zhí)行程序。查看之:
[SDK]$ ls package/cpp-demo/src/ cpp-demo main.cpp main.o Makefile
果然有它!在make時,由于它的存在,編譯組件就認為已經(jīng)有了就不必再編譯,所以才導(dǎo)致了上述的問題。
刪除cpp-demo以及main.o?;氐絊DK,重新make
$ rm -rf build_dir $ make V=s | less
分析打印的信息:
CC="mips-openwrt-linux-uclibc-gcc" GCC="mips-openwrt-linux-uclibc-gcc" CXX="mips-openwrt-linux-uclibc-g++" ... make[4]: Entering directory `/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo' mips-openwrt-linux-uclibc-g++ -Os -pipe -mno-branch-likely -mips32r2 -mtune=34kc -fno-caller-saves -fhonour-copts -Wno-error=unused-but-set-variable \ -msoft-float -mips16 -minterlink-mips16 -I/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/include \ -I/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/target-mips_34kc_uClibc-0.9.33.2/include \ -I/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/usr/include \ -I/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/include \ -c -o main.o main.cpp echo "DEBUG: CXX = mips-openwrt-linux-uclibc-g++" DEBUG: CXX = mips-openwrt-linux-uclibc-g++ mips-openwrt-linux-uclibc-g++ -o cpp-demo main.o make[4]: Leaving directory `/home/hevake_lcj/Workspace/OpenWRT/OpenWrt-SDK/build_dir/target-mips_34kc_uClibc-0.9.33.2/cpp-demo' ...
根據(jù)調(diào)試信息可以知道cpp-demo是用mips-openwrt-linux-uclibs-g++來編譯的。這下應(yīng)該就對了!
再次嘗試將ipk文件傳到目標(biāo)機上并安裝。運行效果如下:
root@OpenWrt:~# cpp-demo This is C++ Demo
成功了!
感謝各位的閱讀,以上就是“怎么編寫C++程序并把它做成ipk包”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對怎么編寫C++程序并把它做成ipk包這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。