• open62541交叉编译


         好久没有做嵌入式Arm Linux 的开发了。最近要将open62541 的应用程序移植到i.mx6u 嵌入式控制器。网络上讲解i.mx6 交叉编译的文章太多了。但是都过于复杂,大多数使用虚拟机实现。其实在ubuntu OS 下,开发ARM 嵌入式应用软件相对是相当简单的。这里记录了在ubuntu Linux 下,交叉编译i.mx 应用软件的过程。

     安装交叉编译工具及其基本库

    目标设备为两种ARM

    NXP i.mx6 基于Arm V7

    RK3399

    arm-linux-gnueabihf-gcc

    imx6 是arm v7 架构,使用arm-linux-gnueabihf-gcc 和 arm-linux-gnueabihf-g++

    1. sudo apt-get update
    2. sudo apt-get install gcc-arm-linux-gnueabihf
    3. sudo apt-get install g++-arm-linux-gnueabihf

       值得注意的是 安装这两个交叉编译器之后,在usr/lib 中自动建立了 /gcc-cross/arm-linux-gnueabihf/11目录,内部包含了gcc 基本的库,例如libc.so 。自己编译的库也copy 到这个目录中。

    g++-aarch64-linux-gnu

       对于Arm v8 64位架构的处理器,例如RK3399 的 cortex-A53 ,需要使用gcc-aarch64-linux-gnu和g++-aarch64-linux-gnu

    1. sudo apt-get install gcc-aarch64-linux-gnu
    2. sudo apt-get install gcc-aarch64-linux-gnu

    关于与目标机的兼容性

    遇到的最大问题是libc.so.6 等动态库不兼容的问题,我部分解决的方法是

    1. 将目标机器上的lib 考到编译机上。

    2。 应用程序使用静态编译。

    测试 gcc

    为了测试安装的交叉编译工具,先编写了一个Test 程序

    1. #include
    2. #include
    3. int main(){
    4. int x;
    5. x=pow(3,2);
    6. printf("%d\n",x);
    7. }

    编译命令

    arm-linux-gnueabihf-gcc test1.c -o test1
    

     编译open62541 的依赖库

    1 如果open62541 Enable NodesetLoad ,需要依赖库libxml.so。

    编译安装方式:

    下载 源码

    使用cmake

    libxml 的选项比较多,容易出错。我做了一些选择。


    2 如果open62541 Enable History ,需要依赖库sqlite3

    编译安装方式:

    编译 open62541

            由于之前安装了ubuntu open62541 库,include 放置在usr/local/include 中。当交叉编译时,仍然使用它,可能会有点差错,比如Eable pub/sub 时,要UA_ENABLE_AMALGAMATION 打勾。

    libxml.so 要指向/gcc-cross/arm-linux-gnueabihf/11。

    编译完成后,copy 到/gcc-cross/arm-linux-gnueabihf/11 中:

    sudo cp libopen62541.so /usr/lib/gcc-cross/arm-linux-gnueabihf/11/libopen62541.so

    编译Opcua 应用程序

    编辑最小server

    1. /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
    2. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
    3. #include
    4. /* Build Instructions (Linux)
    5. * - g++ server.cpp -lopen62541 -o server */
    6. using namespace std;
    7. int main() {
    8. UA_Server *server = UA_Server_new();
    9. // add a variable node to the adresspace
    10. UA_VariableAttributes attr = UA_VariableAttributes_default;
    11. UA_Int32 myInteger = 42;
    12. UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
    13. attr.description = UA_LOCALIZEDTEXT_ALLOC("en-US","the answer");
    14. attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US","the answer");
    15. UA_NodeId myIntegerNodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
    16. UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME_ALLOC(1, "the answer");
    17. UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
    18. UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
    19. UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
    20. parentReferenceNodeId, myIntegerName,
    21. UA_NODEID_NULL, attr, NULL, NULL);
    22. /* allocations on the heap need to be freed */
    23. UA_VariableAttributes_clear(&attr);
    24. UA_NodeId_clear(&myIntegerNodeId);
    25. UA_QualifiedName_clear(&myIntegerName);
    26. UA_StatusCode retval = UA_Server_runUntilInterrupt(server);
    27. UA_Server_delete(server);
    28. return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
    29. }

    编译命令

    aarch64-linux-gnu-g++ server.cpp -o server -lopen62541 -lxml2 -L /home/yao/yao2023/RK3399Project/aarch64-linux-gnu/lib  -static  -I /usr/local/include --std=c++2a

       由于open62541 中包含了xml 动态库。因此要-lxml2.如果将xml编译成为静态库 可能就没有这个问题。

     编译成为静态库,避免libc 等动态库不兼容的问题。

    复制到目标机运行

    scp ./server root@192.168.31.108:/home/application/server
    

    编译 IEC61499 runtime

    aarch64-linux-gnu-g++   ./*.cpp ./FunctionBlocks/*.cpp -I ./modbusTCP   -o uaForteA  -lopen62541  -lxml2 -I /usr/local/include --std=c++2a -L /home/yao/yao2023/RK3399Project/aarch64-linux-gnu/lib  -static

    复制到目标机运行

    Go 语言的交叉编译

    在我们的项目中,有Web 实现设备管理,采用Go 语言编写web 相对NodeJS 更精简一些。下面记录了Go 语言应用程序的交叉编译,这是非常简单的。

    测试代码

    1. # shared.go
    2. package main
    3. import "C"
    4. //export Sum
    5. func Sum(a, b int) int {
    6. return a + b
    7. }
    8. func main(){}

     32-bit arm

    CGO_ENABLED=1 GOOS=linux GOARCH=arm CC=arm-linux-gnueabihf-gcc go build -buildmode=c-shared -o share.so 

    64-bit arm

    CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=aarch64-linux-gnu-gcc-5.3.1 go build -buildmode=c-shared -o share.so 

    构建了一个动态库。 

  • 相关阅读:
    2000-2020年上市公司制造业数据/制造业上市公司数据
    BUUCTF [GXYCTF2019]佛系青年 1
    【Java】-【使用jxl操作excel】
    Linux CentOS 本地yum配置
    32_ue4进阶末日生存游戏开发[接口]
    Qt扫盲-QFutureSynchronizer 理论总结
    Matlab实现DBO-BiTCN-BiGRU-Attention蜣螂算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测
    docker制作java项目镜像
    G-Ghost-RegNet实战:使用G-Ghost-RegNet实现图像分类任务(一)
    sklearn.pipeline的用法介绍
  • 原文地址:https://blog.csdn.net/yaojiawan/article/details/133427959