ARM交叉编译入门及交叉编译第三方库常见问题解析

这篇具有很好参考价值的文章主要介绍了ARM交叉编译入门及交叉编译第三方库常见问题解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 交叉编译是什么?

交叉编译简单说来,就是编译成果物的地儿不是你运行这个成果物的地儿。最常见的场景,就是我们要编译一个 ARM版本 的可执行程序,但我们编译这个 ARM版本 可执行程序的地方,是在一个 x86_x64 的平台上。

2. 为什么需要交叉编译?

绝大部分的原因,是目标平台不具备编译成果物的算力。具体说来,就是ARM平台早期是 并没有 编译代码所需的 算力相关空间 的。所以,不得不借助性能更高的平台来辅助进行编译成果物,然后ARM平台仅负责运行成果物即可。

3. 交叉编译只能在目标平台同一系统上吗?

虽然绝大多数的 ARM Linux系统中编译的成果物是在对应的 x86_x64平台的Linux系统中进行的,所以大多数时候使用Windows平台电脑需要安装一个虚拟机或者连接到某个x86_x64平台的Linux编译服务器中,但实际上这种搭配大多数情况是为了方便,也为了让编译者熟悉Linux环境,但这种搭配并不是唯一的解决方案。

ARM官网 上就能直接下载各种平台( LinuxWindows )的编译工具链,另外一个很常见的第三方工具链制作商,linaro也是对外直接提供可用版本的工具链,但不支持全平台, linaro gnu。

如果上述两个网站你都觉得不是很符合自己的开发板,那么你也可以自己动手做一个链子,符合目标平台的交叉编译链制作及简单分析。 这里主要使用crosstool-ng这个工具进行的制作,自己做链子的好处是你可以自己按需选择对应的gcc版本,以及glibc版本和一些其他重要基础库的版本。而上面现成的链子可能并不刚好是你需要的版本搭配。

4. 如何编译一个第三方开源库?

以下编译前提均假设编译人员已经获得了一个可以使用的交叉编译工具链,并且已经将编译工具链的可执行程序设置进环境变量。

4.1 最常见也是最简单的编译方式

大多数的简单第三方库,均可以尝试以下的方式。这里的简单,值得是不额外依赖一些其他第三方库的库。

configure --host=arm-linux-gnueabi  --prefix=${PWD}/build
make
make install

一般验证自己是不是编译的正确的主要检查步骤就是,在make的时候查看对应输出打印,如果开头的的编译的确是对应编译工具链名称的开头,那么至少配置是对的,这里给个例子:

/bin/sh ../libtool  --tag=CXX   --mode=compile arm-at91-linux-gnueabi-g++ -std=gnu++11 -DHAVE_CONFIG_H -I. -I..  -I/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/include -pthread -I/data1/xiaoyanyi/work/openssllll/include -D_GNU_SOURCE  -g -O2 -pthread -MT asn1.lo -MD -MP -MF .deps/asn1.Tpo -c -o asn1.lo asn1.cpp
libtool: compile:  arm-at91-linux-gnueabi-g++ -std=gnu++11 -DHAVE_CONFIG_H -I. -I.. -I/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/include -pthread -I/data1/xiaoyanyi/work/openssllll/include -D_GNU_SOURCE -g -O2 -pthread -MT asn1.lo -MD -MP -MF .deps/asn1.Tpo -c asn1.cpp  -fPIC -DPIC -o .libs/asn1.o
libtool: compile:  arm-at91-linux-gnueabi-g++ -std=gnu++11 -DHAVE_CONFIG_H -I. -I.. -I/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/include -pthread -I/data1/xiaoyanyi/work/openssllll/include -D_GNU_SOURCE -g -O2 -pthread -MT asn1.lo -MD -MP -MF .deps/asn1.Tpo -c asn1.cpp -o asn1.o >/dev/null 2>&1

make的过程中,输出的打印里的确是以我们指定的host开头的,那么这步骤至少是没问题的了。

4.2.1 简单解释一下configure里面常见通用参数的含义

先简单的介绍一下 configure make make install三部曲每部分是做了什么,然后在展开介绍configure的通用参数。

configure : 通过配置生成makefile文件
make:使用configure生成的Makefile文件进行编译工作
make install:将make生成的成果物文件按照prefix的路径进行复制,有时候也会动态生成一些说明文档

所以大多数时候,configure配置对了,后面两步就一定能走通,99%的编译不过问题基本都是configure的时候配置不对。以下重点讲解configure相关的参数。

4.2.1.1 prefix

这里prefix中文解释就是安装路径,也就是make install的时候,最终这些库会放到哪里去。一般对于交叉编译而言,是需要指定的,因为默认的路径是 /usr/local/,但这路径实际上对于交叉编译而言一定是不行的。因为这个路径通常放的是本身系统的库,如果交叉编译的库放进去后,本身系统也会去检索这个路径下的库,名字虽然匹配上了,但是用不起来,后续会造成极大的麻烦。

这里还有一点需要额外注意的,后文会重新展开这个问题。这里先说结论:

如果你需要编译的库ABC依赖DEF,那么你先编译DEF的时候,最好把prefix设置成自己交叉编译链的 sysroot/usr 中。

4.2.1.2 host

简单解释一下,交叉编译和普通的编译第三方库差异主要在于需要指定host这个变量。这里贴一段标准解释:

System types:
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]

这里仅需要额外强调一点,host这个参数的指定逻辑和使用的目标编译工具链名称有关,假设你的编译工具链的gcc名字叫 arm-at91-linux-gnueabi-gcc,那么这里的host名字就是 arm-at91-linux-gnueabi。具体的逻辑就是把对应链子的 -gcc部分拆掉就是host的名字。其实configure脚本的逻辑也就是对应的反向在host后拼接一个 -gcc而已。

4.2.1.3 enable-xxxxx disable-xxxxx

这两个参数一般是在编译的时候,可配置的打开某些功能或者关闭某些功能的时候,会使用到。每个第三方库的特色不一样,这里推荐遇到编译不过的问题,首先就去看看:


./configure --help

有时候发现你编译的第三方库依赖了过多的其他库,而且这些功能对你并不需要的时候,可以尽可能的--disable-xxxxx--without-xxxx。这样,在后续make的时候,就不会出现某些依赖库找不到的报错了。

4.2.1.4 CXX CC CFLAGS

这些shell环境变量也会产生一定的效果,有时候你百度一些博客教程的时候,会搜到交叉编译的某些指导文档会这么写:


./configure CC=arm-linux-gnueabi-gcc  --prefix=${PWD}/build
make
make install

或者写成这样:

export CC=arm-linux-gnueabi-gcc 
./configure  --prefix=${PWD}/build
make
make instal

这两种手法的思路一致的,都是利用./configure 脚本是可以阅读当前shell环境变量中的CC,并且将这个环境变量替换到脚本里,从而实现CC替换成对应链子的目的。相关解释同样可以在--help中看到

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>

但需要注意的一点是:这种方法有一些隐患,主要在于在很多时候,交叉编译并不是把gcc变成arm-linux-gnueabi-gcc一切就完事了。我们可以在Makefile中和交叉编译链的bin路径中看到如下打印:

(base) xiaoyanyi@snmp++-3.5.0$ls ~/cross-tool/arm-at91-linux-gnueabi/bin
arm-at91-linux-gnueabi-addr2line     arm-at91-linux-gnueabi-gcc-4.9.2   arm-at91-linux-gnueabi-nm
arm-at91-linux-gnueabi-ar            arm-at91-linux-gnueabi-gcc-ar      arm-at91-linux-gnueabi-objcopy
arm-at91-linux-gnueabi-as            arm-at91-linux-gnueabi-gcc-nm      arm-at91-linux-gnueabi-objdump
arm-at91-linux-gnueabi-c++           arm-at91-linux-gnueabi-gcc-ranlib  arm-at91-linux-gnueabi-populate
arm-at91-linux-gnueabi-cc            arm-at91-linux-gnueabi-gcov        arm-at91-linux-gnueabi-ranlib
arm-at91-linux-gnueabi-c++filt       arm-at91-linux-gnueabi-gdb         arm-at91-linux-gnueabi-readelf
arm-at91-linux-gnueabi-cpp           arm-at91-linux-gnueabi-gprof       arm-at91-linux-gnueabi-size
arm-at91-linux-gnueabi-ct-ng.config  arm-at91-linux-gnueabi-ld          arm-at91-linux-gnueabi-strings
arm-at91-linux-gnueabi-elfedit       arm-at91-linux-gnueabi-ld.bfd      arm-at91-linux-gnueabi-strip
arm-at91-linux-gnueabi-g++           arm-at91-linux-gnueabi-ldd
arm-at91-linux-gnueabi-gcc           arm-at91-linux-gnueabi-ld.gold

有些Makefile生成的环境中还需要使用ARNMRANLIB等等,这些东西也需要使用对应的交叉编译工具链版本的程序。而上述的CC手法仅仅替换了一个。所以为什么是存在风险和后续还会遇到问题的。

这里推荐,如果能用host,就优先使用host指定,这种方式相当于自动帮你设置了上述每一个需要替换的变量。

在极少数的时候,host不被confiugre支持,那么能用的方法只有这种了,但同时也是最不同推荐的。

4.2.2 对于编译自依赖的第三方库族的推荐方法

有时候,我们使用的第三方库有两层甚至多层,底层他们自己开发了一个基础库,然后在自己的基础库上,封了一层应用。例如protobuf和grpc,snmp++和agent++。这个时候,我们需要先编译基础库,然后在编译应用库。这一点很容易理解,从下到上,但对于交叉编译来说,又有一点需要注意的。主要和 prefix 有关。

当我们编译完基础库之后,一般make install之后,成果物大多情况是这样的[假设我们安装到了一个build目录]:

(base) xiaoyanyi@build$ls
bin  include  lib

bin: 目录一般是这个库的一些demo样例或者一些可执行程序。
include:目录一般就是这个第三方库的头文件
lib:目录一般就是这个第三方库的静态、动态库文件

那么在编译上层应用库的时候,有些教程会推荐按照configure中的指定底层库路径宏变量的方式,去显式指定对应路径。

例如agent++这个库,依赖snmp++,其中agent++的confiugre文件里有这样一个变量:

Some influential environment variables:
  PKG_CONFIG  path to pkg-config utility
  PKG_CONFIG_PATH
              directories to add to pkg-config's search path
  PKG_CONFIG_LIBDIR
              path overriding pkg-config's built-in search path
  CXXCPP      C++ preprocessor
  snmp_CFLAGS C compiler flags for snmp, overriding pkg-config
  snmp_LIBS   linker flags for snmp, overriding pkg-config
  LT_SYS_LIBRARY_PATH
              User-defined run-time library search path.

这里可以通过snmp_LIB这个变量显式指定去libsnmp++.so的位置。这种方式在表面上是能够通过编译并且不会出现什么太大问题的。但会买下一个隐患在于后续使用库或者维护的时候会出现问题。这里需要讲解造成这个隐患问题的另外两个文件。

4.2.2.1 *.la

一般编译完成的第三方库的lib文件夹下面,会有一个对应扩展名为la的文件。

例如:

(base) xiaoyanyi@lib$ls
libsnmp++.a  libsnmp++.la  libsnmp++.so  libsnmp++.so.35  libsnmp++.so.35.0.0  pkgconfig

这个la文件实际上并不是一个静/动态库程序,而是一个配置文件,我们可以直接vim打开:

# libsnmp++.la - a libtool library file
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-14
#
# Please DO NOT delete this file!
# It is necessary for linking the library.

# The name that we can dlopen(3).
dlname='libsnmp++.so.35'

# Names of this library.
library_names='libsnmp++.so.35.0.0 libsnmp++.so.35 libsnmp++.so'

# The name of the static archive.
old_library='libsnmp++.a'

# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=' -pthread'

# Libraries that this one depends upon.
dependency_libs=' -lssl -lcrypto 
/data1/xiaoyanyi/cross-tool/arm-at91-linux-gnueabi/arm-at91-linux-gnueabi/lib/libstdc++.la'

# Names of additional weak libraries provided by this library
weak_library_names=''

# Version information for libsnmp++.
current=35
age=0
revision=0

# Is this an already installed library?
installed=yes

# Should we warn about portability when linking against -modules?
shouldnotlink=no

# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''

# Directory that this library needs to be installed in:
libdir='/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/build/lib'

关键的问题就在最后的libdir里,这个路径指明了这个动态库的安装路径,在连接的过程中,如果有动态库依赖动态库的情况,gcc的连接应用会顺着路径去查找随影目标文件。而如果我们安装的时候,就随意选一个build目录。最后即便是把这个路径放到了sysroot里去之后,这个la文件里面的内容依旧不会变,导致最后就找不到了。

4.2.2.2 pkgconfig *.pc

大多数库编完之后,除了上述的la,其实大家也可以在lib里面找到有一个pkgconfig文件夹,里面会有一个对应的pc文件。

这个文件和la文件的作用极为相似,也是一个配置文件,我们可以打开看看。


prefix=/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/build
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
modules=

Name: snmp++
Version: 3.5.0
Description: SNMP C++ framework version 3
Requires:
Libs: -L${libdir} -lsnmp++
Libs.private:  -lssl -lcrypto
Cflags: -I${includedir}

这里造成错误的原因是因为prefix这个变量也是会因为随意指定从而即便pc文件的位置移动也无法正确索引。pc文件主要是pkg-config这个应用为了编译的时候自动指定FLAGS和自动找库用的。

4.2.2.3 那么应该安装在哪里比较合适呢?

这里推荐的路径是安装在编译工具链的sysroot中。

一般用crosstool-ng做的交叉工具链,对应的sysroot是在

${host}/${host}/sysroot/

对于其他的链子,基本也都有一个sysroot,可以自行查找。而我们安装一般的第三方库,一般推荐放在sysroot中的usr中,因为不是系统库,而是用户自己制作的。

这个路径下的,例如我做了一个链子,host是 arm-at91-linux-gnueabi,那么对应的sysroot/usr路径是:

arm-at91-linux-gnueabi/arm-at91-linux-gnueabi/sysroot/usr/

所以绝大部分的时候,将第三方库的prefix指定为上述路径,可以直接将第三方库安装到编译工具链中,从而达到后续编译其他库的时候,链子会自动索引已经安装过的库,不需要显示指定对应路径的目的。

但这里同样有一个风险点:如果对应第三方库的更新较为频繁,那么就可能存在要编译的新库但sysroot里有个老库的场景。这里推荐是更新较为频繁的库不要放到sysroot里去

4.2 一些不常见但是常用的第三方库可能的编译方式

4.1里介绍的手法基本上能处理绝大多数的第三方库,但仍旧有某些库的configure写的比较奇特,按照常规三部曲无法解决的。一般通用的处理思路还是好好阅读configure --help,同时这里重点解释两个场景。

4.2.1 常见开源加密算法库OpenSSL

这个动态库的交叉编译就不合适上述的情况,configure中并没有指定host的能力,这里推荐的建议是这样,先说结果:


./Configure linux-armv4 no-asm shared

这个库为什么会这么输入,我们又是如何知道的呢?其实还是看configure --help就能发现端倪。

(base) xiaoyanyi@openssl-1.0.2t$./Configure --help
Configuring for
Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimental-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-dso] [no-krb5] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--test-sanity] os/compiler[:flags]

pick os/compiler from:
BC-32 BS2000-OSD BSD-generic32 BSD-generic64 BSD-ia64 BSD-sparc64 BSD-sparcv8
BSD-x86 BSD-x86-elf BSD-x86_64 Cygwin Cygwin-x86_64 DJGPP MPE/iX-gcc OS2-EMX
OS390-Unix QNX6 QNX6-i386 ReliantUNIX SINIX SINIX-N UWIN VC-CE VC-WIN32
VC-WIN64A VC-WIN64I aix-cc aix-gcc aix3-cc aix64-cc aix64-gcc android
android-armv7 android-mips android-x86 android64-aarch64 aux3-gcc
beos-x86-bone beos-x86-r5 bsdi-elf-gcc cc cray-j90 cray-t3e darwin-i386-cc
darwin-ppc-cc darwin64-ppc-cc darwin64-x86_64-cc dgux-R3-gcc dgux-R4-gcc
dgux-R4-x86-gcc dist gcc hpux-cc hpux-gcc hpux-ia64-cc hpux-ia64-gcc
hpux-parisc-cc hpux-parisc-cc-o4 hpux-parisc-gcc hpux-parisc1_1-cc
hpux-parisc1_1-gcc hpux-parisc2-cc hpux-parisc2-gcc hpux64-ia64-cc
hpux64-ia64-gcc hpux64-parisc2-cc hpux64-parisc2-gcc hurd-x86 iphoneos-cross
irix-cc irix-gcc irix-mips3-cc irix-mips3-gcc irix64-mips4-cc irix64-mips4-gcc
linux-aarch64 linux-alpha+bwx-ccc linux-alpha+bwx-gcc linux-alpha-ccc
linux-alpha-gcc linux-aout linux-armv4 linux-elf linux-generic32
linux-generic64 linux-ia32-icc linux-ia64 linux-ia64-icc linux-mips32
linux-mips64 linux-ppc linux-ppc64 linux-ppc64le linux-sparcv8 linux-sparcv9
linux-x32 linux-x86_64 linux-x86_64-clang linux-x86_64-icc linux32-s390x
linux64-mips64 linux64-s390x linux64-sparcv9 mingw mingw64 ncr-scde
netware-clib netware-clib-bsdsock netware-clib-bsdsock-gcc netware-clib-gcc
netware-libc netware-libc-bsdsock netware-libc-bsdsock-gcc netware-libc-gcc
newsos4-gcc nextstep nextstep3.3 osf1-alpha-cc osf1-alpha-gcc purify qnx4
rhapsody-ppc-cc sco5-cc sco5-gcc solaris-sparcv7-cc solaris-sparcv7-gcc
solaris-sparcv8-cc solaris-sparcv8-gcc solaris-sparcv9-cc solaris-sparcv9-gcc
solaris-x86-cc solaris-x86-gcc solaris64-sparcv9-cc solaris64-sparcv9-gcc
solaris64-x86_64-cc solaris64-x86_64-gcc sunos-gcc tandem-c89 tru64-alpha-cc
uClinux-dist uClinux-dist64 ultrix-cc ultrix-gcc unixware-2.0 unixware-2.1
unixware-7 unixware-7-gcc vos-gcc vxworks-mips vxworks-ppc405 vxworks-ppc60x
vxworks-ppc750 vxworks-ppc750-debug vxworks-ppc860 vxworks-ppcgen
vxworks-simlinux debug debug-BSD-x86-elf debug-VC-WIN32 debug-VC-WIN64A
debug-VC-WIN64I debug-ben debug-ben-darwin64 debug-ben-debug
debug-ben-debug-64 debug-ben-debug-64-clang debug-ben-macos
debug-ben-macos-gcc46 debug-ben-no-opt debug-ben-openbsd
debug-ben-openbsd-debug debug-ben-strict debug-bodo debug-darwin-i386-cc
debug-darwin-ppc-cc debug-darwin64-x86_64-cc debug-geoff32 debug-geoff64
debug-levitte-linux-elf debug-levitte-linux-elf-extreme
debug-levitte-linux-noasm debug-levitte-linux-noasm-extreme debug-linux-elf
debug-linux-elf-noefence debug-linux-generic32 debug-linux-generic64
debug-linux-ia32-aes debug-linux-pentium debug-linux-ppro debug-linux-x86_64
debug-linux-x86_64-clang debug-rse debug-solaris-sparcv8-cc
debug-solaris-sparcv8-gcc debug-solaris-sparcv9-cc debug-solaris-sparcv9-gcc
debug-steve-opt debug-steve32 debug-steve64 debug-vos-gcc

NOTE: If in doubt, on Unix-ish systems use './config'.

这个库显式指定了所有它能支持的平台种类,所以我们只能按照这个指定了。这样指定完之后,需要把生成的Makefile中对应宏定义进行显式修改,包括但不限于CCARNMRANLIBCXX等等。

4.2.2 有些库压根就没有configure,需要用cmake

有些开源库就没给configure,但是能看到cmakelist的文件,那么这个时候,把cmakelist当做configure就好,但是它的指定写法会稍显不同。一般需要提供一个对应的cmake配置,对于我们交叉编译来说,需要指定对应的host系统名称CMAKE_SYSTEM_NAME和处理器名称CMAKE_SYSTEM_PROCESSOR,然后需要指定对应的编译链路径CMAKE_C_COMPILERCMAKE_CXX_COMPILER

这里给出一个样例:

 #arm.cmake
 set(CMAKE_SYSTEM_NAME Linux)
 set(CMAKE_SYSTEM_PROCESSOR arm)
 
 set(tools /data1/xiaoyanyi/cross-tool/arm-imx6ul-linux-gnueabihf/bin/arm-imx6ul-linux-gnueabihf-)
 set(CMAKE_C_COMPILER ${tools}gcc)
 set(CMAKE_CXX_COMPILER ${tools}g++)

cmake文件准备好后,就可以直接cmake了,机理是和configure一样的:

cmake CMakeLists.txt -DCMAKE_TOOLCHAIN_FILE=./arm.cmake

上述命令执行完后,最终会生成一个Makefile文件,接着makemake install就好了。

5. 总结

  • 绝大多数场景,交叉编译的时候configuremakemake install三部曲就好,与普通编译不一样的是需要指定host

  • 自依赖第三方库在不频繁迭代更新的条件下,建议安装到交叉编译链的sysroot目录中

  • 如果怎么编译都有点问题,建议仔细阅读configure --help或者README分析查找端倪文章来源地址https://www.toymoban.com/news/detail-425963.html

到了这里,关于ARM交叉编译入门及交叉编译第三方库常见问题解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 模拟.NET应用场景,综合应用反编译、第三方库调试、拦截、一库多版本兼容方案

    免责声明 使用者本人对于传播和利用本公众号提供的信息所造成的任何直接或间接的后果和损失负全部责任。公众号及作者对于这些后果不承担任何责任。如果造成后果,请自行承担责任。谢谢! 大家好,我是沙漠尽头的狼。 本文首发于Dotnet9,结合前面两篇(如何在没有第

    2024年02月08日
    浏览(29)
  • 编译一份适用于鸿蒙ArkTs的so动态库教学,提供给第三方导入并使用

    转载注明出处 这里以cJSON为例,只需要使用到仓库的cJSON.h和cJSON.c 打开DevEco-Studio创建一个native项目 选项随意填写 将cJSON.c和cJSON.h放到项目自动创建的cpp文件夹下 在cmakelists.txt添加两行 add_library(cjson SHARED cJSON.c) target_link_libraries(cjson PUBLIC libace_napi.z.so) cjson表示最终导出的so库的

    2024年01月19日
    浏览(34)
  • SpringBoot整合第三方技术 -- SpringBoot快速入门保姆级教程(三)

    为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。 (博客的参考源码可以在我主页的资源里找到,如果在学习的

    2024年02月09日
    浏览(33)
  • 在ARM板上实现qt虚拟键盘 Qwidget实现 官方虚拟键盘、第三方虚拟键盘qtvirtualkeyboard //Qwidget最简单但效果不是最好

    在使用qt的虚拟键盘以前,我的开发板qt环境中并没有安装虚拟键盘库,所以这里还会顺便介绍如何在开发板上已安装qt环境的前提下,继续更新qt的组件。 开发板qt版本:5.15.2 在这里,我默认你已经有自己动手交叉编译过qt源码了,否则你将缺少部分细节和前置知识。首先在

    2024年04月09日
    浏览(220)
  • Flink保姆级教程,超详细,教学集成多个第三方工具(从入门到精通)

    目录 一.Flink简介 Flink发展历程 Flink特性 二、Flink 部署及启动 1. 本地执行 (Local Execution) 2. Standalone 集群部署 2.1 会话模式(Session Mode) 2.2 单作业模式(Per-Job Mode)和应用模式(Application Mode) 3. 资源管理器集成部署 三.Flink架构和执行原理 Flink架构 任务槽和资源 Flink资源管

    2024年04月29日
    浏览(30)
  • 从入门到精通:掌握Spring IOC/DI配置管理第三方bean的技巧

    以后我们会用到很多第三方的bean,我们以数据源是 Druid(德鲁伊) 和 C3P0 来配置举个例子。 1.1.1 环境准备 先来准备下案例环境: 1.1.2 思路分析 需求:使用Spring的IOC容器来管理Druid连接池对象 1.使用第三方的技术,需要在pom.xml添加依赖 2.在配置文件中将【第三方的类】制作成一个

    2024年02月02日
    浏览(35)
  • Python第三方库安装教程、什么是第三方库

    Python有一个全球社区:https://pypi.org/,在这里我们可以搜索任何主题的Python第三方库。PyPI全称是Python Package Index,指的是Python包的索引,它由PSF(Python Software Foundation)来维护,并且展示全球Python计算生态。 我们需要学会利用PyPI的主站检索,找到我们使用和关心的Python第三方

    2024年02月03日
    浏览(82)
  • 引入第三方字体库 第三方字体库Google Fonts

    googlefonts官方网站 googlefonts中国网站 本人是在微信小程序中引入 在static中建一个文件夹font-family 例如字体链接:https://fonts.font.im/css?family=Kirang+Haerang 将该链接的返回的资源的复制到css文件中 font-family.css main.js引入 微信小程序不校验合法域名就能看到结果

    2024年02月16日
    浏览(43)
  • Python第三方库安装——使用vscode、pycharm安装Python第三方库

    在这里介绍vscode、Pycharm安装python第三方库的方法。 操作系统:windows10 专业版 环境如下: Pycharm Comunity 2022.3 Visual Studio Code 2019 Python 3.8 pip:23.0.1 pycharm是一款很强大的、专用于写python的ide。 小白式安装第三方库往往能给初学者一种 “高级感” ,而对于使用惯了Linux的人而言

    2024年02月03日
    浏览(46)
  • Python第三方库批量下载到本地,并离线批量安装第三方库

    鉴于公司内网安装的python版本为python3.6.5,而此时又需要安装第三方库pytest,本来是想直接在Python官网PyPI直接搜对应可匹配跑python3.6.5版本的pytest进行下载然后传到内网安装即可,但是发现pytest依赖别的第三方库,根据报错装了几个依赖的第三方库之后,发现还是一堆的问题

    2024年02月07日
    浏览(68)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包