gstreamer移植qnx:交叉编译glib

Posted 玄道公子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gstreamer移植qnx:交叉编译glib相关的知识,希望对你有一定的参考价值。

一、简介

​ 这里以glib的2.63.0版本,QNX系统的版本是:6.6 。这里是为了编译gstreamer的依赖库,也就是说最终目标,是将gstreamer移植到QNX6.6系统上。 我选择的是gstreamer 1.16,他需要的glib版本是2.40以上,因此就索性使用最新的glib版本。 编译用的host系统是Ubuntu18.04。

二、准备cross-file

​ 因为最新的glib其构建系统是使用的meson, 而我们这边是要交叉编译,所以需要准备一个cross-file的来配置交叉编译工具链

2.1 填写工具链

​ 首先是需要填写CPU和系统信息,以及工具链信息, 顺便还可以填写编译完成之后,安装的目录,其内容如下:

[host_machine]
system = 'qnx'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'

[binaries]
c = 'arm-unknown-nto-qnx6.6.0eabi-gcc'
cpp = 'arm-unknown-nto-qnx6.6.0eabi-g++'
ar = 'arm-unknown-nto-qnx6.6.0eabi-ar'
strip = 'arm-unknown-nto-qnx6.6.0eabi-strip'

[paths]
prefix = '/media/guwen/workspace/project/gstreamer/out'
      

2.2 填写编译flag信息

​ 第一个就是需要定义一个 _QNX_SOURCE宏,不然在编译和POSIX thread相关的部分时,就会出现“error: #error POSIX Scheduling needs P1003.1b-1993 or later” 这类似的错误。

[properties]
c_args = ['-D_QNX_SOURCE=1']
c_link_args = []

修改之后的完整版cross-file文件,qnx_arm.txt如下所示:

host_machine]
system = 'qnx'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'


[binaries]
c = 'arm-unknown-nto-qnx6.6.0eabi-gcc'
cpp = 'arm-unknown-nto-qnx6.6.0eabi-g++'
ar = 'arm-unknown-nto-qnx6.6.0eabi-ar'
strip = 'arm-unknown-nto-qnx6.6.0eabi-strip'


[properties]
c_args = ['-D_QNX_SOURCE=1']
c_link_args = []


[paths]
prefix = '/media/guwen/workspace/project/gstreamer/out'

三、 修改meson.build

​ 因为某些特性,qnx6.6的toolchain里面没有,比如xattr, 因此这里需要修改meson的option选项,这里有两种方式:

  • 直接在meson的命令行参数,以 -Dxattr=false的方式进
  • 修改glib里面的meson.build文件里面default_options部分

​ 这里为了方便,就选择了修改meson.build 文件,免得每次敲命令 都要带一长串参数。 当然,也可以把这个配置过程写到一个shell脚本里面。

​ 修改后的default_options如下所示:

  default_options : [
    'buildtype=release',
    'warning_level=1',
    'c_std=gnu99',
    'xattr=false',
    'force_posix_threads=true',
    'libmount=false'
  ]  
  

​ qnx的libintl没有ngettext这个函数,因此需要使用glib自带的libintl库,

​ 修改前的原始版本:

# First check in libc, fallback to libintl, and as last chance build
# proxy-libintl subproject.
# FIXME: glib-gettext.m4 has much more checks to detect broken/uncompatible
# implementations. This could be extended if issues are found in some platforms.
if cc.has_function('ngettext')
  libintl = []
  have_bind_textdomain_codeset = cc.has_function('bind_textdomain_codeset')
else
  libintl = cc.find_library('intl', required : false)
  if not libintl.found()
    libintl = subproject('proxy-libintl').get_variable('intl_dep')
    have_bind_textdomain_codeset = true  # proxy-libintl supports it
  else
    have_bind_textdomain_codeset = cc.has_function('bind_textdomain_codeset',
                                                  dependencies : libintl)
  endif
endif

​ 修改之后的版本:

# First check in libc, fallback to libintl, and as last chance build
# proxy-libintl subproject.
# FIXME: glib-gettext.m4 has much more checks to detect broken/uncompatible
# implementations. This could be extended if issues are found in some platforms.
if cc.has_function('ngettext')
  libintl = []
  have_bind_textdomain_codeset = cc.has_function('bind_textdomain_codeset')
else
  #libintl = cc.find_library('intl', required : false)
  #if not libintl.found()
    libintl = subproject('proxy-libintl').get_variable('intl_dep')
    have_bind_textdomain_codeset = true  # proxy-libintl supports it
  #else
  #  have_bind_textdomain_codeset = cc.has_function('bind_textdomain_codeset',
  #                                                 dependencies : libintl)
  #endif
endif

四、修改 gio目录下的内容

4.1 修改gio目录下的meson.build

​ 因为qnx里面没有libresolv,也没有libbind, res_query函数是在libsocket库里面。因此需要修改gio目录下的meson.build文件。

原始内容如下:

if host_system != 'windows'
  # res_query()
  res_query_test = '''#include <resolv.h>
                      int main (int argc, char ** argv) 
                        return res_query("test", 0, 0, (void *)0, 0);
                      '''
  res_query_test_full = '''#include <sys/types.h>
                           #include <netinet/in.h>
                           #include <arpa/nameser.h>
                        ''' + res_query_test
  if not cc.links(res_query_test_full, name : 'res_query()')
    if cc.links(res_query_test_full, args : '-lresolv', name : 'res_query() in -lresolv')
      network_libs += [ cc.find_library('resolv') ]
      network_args += [ '-lresolv' ]
    elif cc.links(res_query_test, args : '-lbind', name : 'res_query() in -lbind')
      network_libs += [ cc.find_library('bind') ]
      network_args += [ '-lbind' ]
    else
      error('Could not find res_query()')
    endif
  endif

  # socket()
  socket_test = '''#include <sys/types.h>
                   #include <sys/socket.h>
                   int main (int argc, char ** argv) 
                     return socket(1, 2, 3);
                   '''
  if not cc.links(socket_test, name : 'socket()')
    if cc.links(socket_test, args : '-lsocket', name : 'socket() in -lsocket')
      network_libs += [ cc.find_library('socket') ]
      network_args += [ '-lsocket' ]
    else
      error('Could not find socket()')
    endif
  endif

修改之后如下:

if host_system != 'windows'
  # res_query()
  res_query_test = '''#include <resolv.h>
                      int main (int argc, char ** argv) 
                        return res_query("test", 0, 0, (void *)0, 0);
                      '''
  res_query_test_full = '''#include <sys/types.h>
                           #include <netinet/in.h>
                           #include <arpa/nameser.h>
                        ''' + res_query_test
  if not cc.links(res_query_test_full, name : 'res_query()')
    if cc.links(res_query_test_full, args : '-lsocket', name : 'res_query() in -lsocket')
      network_libs += [ cc.find_library('socket') ]
      network_args += [ '-lsocket' ]
    elif cc.links(res_query_test, args : '-lbind', name : 'res_query() in -lbind')
      network_libs += [ cc.find_library('bind') ]
      network_args += [ '-lbind' ]
    else
      error('Could not find res_query()')
    endif
  endif

  # socket()
  socket_test = '''#include <sys/types.h>
                   #include <sys/socket.h>
                   int main (int argc, char ** argv) 
                     return socket(1, 2, 3);
                   '''
  if not cc.links(socket_test, name : 'socket()')
    if cc.links(socket_test, args : '-lsocket', name : 'socket() in -lsocket')
      network_libs += [ cc.find_library('socket') ]
      network_args += [ '-lsocket' ]
    else
      error('Could not find socket()')
    endif
  endif

4.2 修改gunixmounts.c

​ 因为glib没有实现qnx平台的 _g_get_unix_mounts 和 _g_get_unix_mount_points 以及get_mtab_monitor_file 函数,因此编译会出现如下错误:

…/gio/gunixmounts.c:954:2: error: #error No _g_get_unix_mounts() implementation for system
…/gio/gunixmounts.c:1477:2: error: #error No g_get_mount_table() implementation for system

​ 因此需要在 954行和1477行添加qnx版本的的实现,其实也不是实现,就是留个空,代码如下:

//在954行添加
/* Common code 2 */
#elif defined(__QNX__)
static GList* _g_get_unix_mounts (void)

    return NULL;


static const char* get_mtab_monitor_file (void)

	return NULL;


#else
#error No _g_get_unix_mounts() implementation for system
#endif


//在1477行添加
/* Common code 2 */
#elif defined(__QNX__)
static GList * _g_get_unix_mount_points (void)

    return NULL;


#else
#error No g_get_mount_table() implementation for system
#endif

五、编译过程

  • 新建build目录并进入build目录:
mkdir build
cd build
  • meson配置
meson .. --cross-file ../qnx_arm.txt
  • ninja编译和安装
ninja
ninja install

以上是关于gstreamer移植qnx:交叉编译glib的主要内容,如果未能解决你的问题,请参考以下文章

gstreamer移植qnx:交叉编译gstreamer之 libgstreamer

基于FS4412嵌入式系统移植 glib库的交叉编译与移植

基于arm5718的交叉编译gstreamer移植

基于arm5718的交叉编译gstreamer移植

gstreamer移植qnx:概览篇

gstreamer移植qnx:编写gstreamer插件audio sink和video sink