一文搞懂交叉编译,Windows和Linux的交叉编译

2023-05-16

文章目录

    • 什么是交叉编译
      • 为什么要交叉编译
      • 工具链的种类
    • 我们应该怎样建立交叉编译环境
    • 在Windows下交叉编译和调试树莓派软件
      • 一、Windows下编译树莓派程序
      • 二、用WSL来编译树莓派程序
      • 三、通过gdbserver远程调试
    • 基于 MinGW 搭建 Windows 下的交叉编译环境
      • 前言
      • 环境
      • 下载安装 MinGW
      • 从最简单的开始
      • 复杂一点的

什么是交叉编译

在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码,我们就称这种编译器支持交叉编译。这个编译过程就叫交叉编译。简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓平台,实际上包含两个概念:体系结构(Architecture)、操作系统(OperatingSystem)。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。举例来说,我们常说的x86 Linux平台实际上是Intel x86体系结构和Linux for x86操作系统的统称;而x86 WinNT平台实际上是Intel x86体系结构和Windows NT for x86操作系统的简称。

交叉编译这个概念的出现和流行是和嵌入式系统的广泛发展同步的。我们常用的计算机软件,都需要通过编译的方式,把使用高级计算机语言编写的代码(比如C代码)编译(compile)成计算机可以识别和执行的二进制代码。比如,我们在Windows平台上,可使用Visual C++开发环境,编写程序并编译成可执行程序。这种方式下,我们使用PC平台上的Windows工具开发针对Windows本身的可执行程序,这种编译过程称为native compilation,中文可理解为本机编译。然而,在进行嵌入式系统的开发时,运行程序的目标平台通常具有有限的存储空间和运算能力,比如常见的ARM 平台,其一般的静态存储空间大概是16到32MB,而CPU的主频大概在100MHz到500MHz之间。这种情况下,在ARM平台上进行本机编译就不太可能了,这是因为一般的编译工具链(compilation tool chain)需要很大的存储空间,并需要很强的CPU运算能力。为了解决这个问题,交叉编译工具就应运而生了。通过交叉编译工具,我们就可以在CPU能力很强、存储控件足够的主机平台上(比如PC上)编译出针对其他平台的可执行程序。

要进行交叉编译,我们需要在主机平台上安装对应的交叉编译工具链(crosscompilation tool chain),然后用这个交叉编译工具链编译我们的源代码,最终生成可在目标平台上运行的代码。常见的交叉编译例子如下:

1、在Windows PC上,利用ADS(ARM 开发环境),使用armcc编译器,则可编译出针对ARM CPU的可执行代码。

2、在Linux PC上,利用arm-linux-gcc编译器,可编译出针对Linux ARM平台的可执行代码。

3、在Windows PC上,利用cygwin环境,运行arm-elf-gcc编译器,可编译出针对ARM CPU的可执行代码。


为什么要交叉编译

交叉编译其实是相对于本地编译(native build)来说的,我相信大家最开始学习 C/C++ 这些语言的时候,都是在电脑上写程序,然后在电脑上编译生成可执行文件,最后在电脑上运行。程序的编辑——》编译——》运行,整个过程都是在一台 X86 电脑上。

当我们开始接触嵌入式开发后,事情变的不一样了,你在电脑上写程序,在电脑上编译出可执行文件,最后这个可执行文件需要下载到你的开发板上运行。程序最后运行的环境变了,比如你的开发板是基于 Arm 的——程序在 X86 上编辑,编译,最终运行在另一个和 X86 完全不同的架构的 Arm 芯片上。

img

之所以整个流程变成了这个样子,这是由嵌入式系统的特性决定的:一般嵌入式系统里面使用的芯片性能都比较弱,而且绝大部分都不能像 X86 一样运行 Windows/Ubuntu 桌面系统,即使能运行,性能也很弱,无法给你提供一个在开发板上写代码、编译代码的环境。所以我们还是离不开 X86 电脑强大高效的桌面环境进行软件开发。

但是这样有一个问题,X86、Arm、MIPS、RISC-V 这些芯片,它们的指令集是由不同的组织或者公司设计的,彼此并不兼容——Arm 和 MIPS 的 CPU 无法运行以 X86 的指令集编码的程序,反之亦然。所以我们要在 X86 的电脑上编译出能够在 Arm 上运行的程序,我们必须明确告诉编译器,编译生成的可执行文件需要以 Arm 指令集的标准编码。为了让这个流程变得简单,开发者们为不同的芯片开发了不同的编译器,比如针对 Arm 平台的 arm-linux-gcc,针对 mips 平台的 mips-linux-gnu-gcc,这些编译器都是基于 GCC 针对具体的架构指令集进行对应配置,所以它们在运行的时候就就会生成和该目标平台对应的可执行文件。

这篇文章主要讲 Arm 的交叉编译,所以这里后面都以 Linux 开发环境下的 Arm gcc 为例。

工具链的种类

GCC 的命名规则为: arch [-vendor] [-os] [-(gnu)eabi]-gcc

比如 arm-linux-gnueabi-gccarm-none-eabi-gccaarch64-linux-gnu-gcc

  • 带 [] 的是可选部分。
  • arch: 芯片架构,比如 32 位的 Arm 架构对应的 arch 为 arm,64 位的 Arm 架构对应的 arch 为 aarch64。
  • vendor :工具链提供商,大部分工具链名字里面都没有包含这部分。
  • os :编译出来的可执行文件(目标文件)针对的操作系统,比如 Linux。

arm-none-eabi-gcc 一般适用用于 Arm Cortex-M/Cortex-R 平台,它使用的是 newlib 库。

arm-linux-gnueabi-gcc 和 aarch64-linux-gnu-gcc 适用于 Arm Cortex-A 系列芯片,前者针对 32 位芯片,后者针对 64 位芯片,它使用的是 glibc 库。可以用来编译 u-boot、linux kernel 以及应用程序。

另外需要补充一点的是,32 位的 Arm 和 64 位的 Arm,它们的指令集是不同的,所以需要使用不同的工具链。当然,Arm64 为了保证前向兼容,提供了一个 32 位的兼容模式,所以我们用 arm-linux-gnueabi-gcc 编译的应用程序也是可以直接在Arm64 的系统上运行的,但是 Linux Kernel 和 U-Boot 就不行,除非你提前把 CPU 切换到 32 位模式。曾经有个项目使用了一颗四核的 Arm64 芯片,但是内存只有64M,为了节省空间,在 CPU 运行到 U-Boot 之前,我们就把它切到了 32 位模式,后面的 U-Boot、Linux Kernel,应用全部都用 32 位编译,加上 Thumb 指令集,节省了不少空间。

我们应该怎样建立交叉编译环境

OK,这里来到了重点。我们知道了什么是交叉编译环境,那我们到底应该怎么开始呢?
网上有很多建立交叉编译环境的傻瓜教程,比如:

  1. IBM的《如何为嵌入式开发建立交叉编译环境》
  2. huihoo的《一步一步的制作arm-linux交叉编译环境

​ 这些都是很权威的交叉编译环境建立的教程,尽管如此我们还是会被这些东东“吓到”;可是从另外一个角度来看我们没有必要来这样做,因为我们的目的是应用这个环境来开发我们的应用程序,所以我们应该尽可
能少的在建立环境的阶段纠缠不清。好在情况不是很坏,网上有很多已经编译好的交叉编译环境的package
供我们下载使用。比如http://ftp.kelp.or.kr/pub/arm-linux/toolchain/,http://ftp.handhelds.org/projects/toolchain/,http://www.handhelds.org/download/projects/toolchain/,有几款公认的比较稳定的版本:

  • 2.95.3
  • 3.4.5
  • 4.2.1

​ 一般我们编译程序和编译器的版本没有关系,不乏特殊情况,比如在移植Qtopia4.x.x的时候,官方文档
就要求使用3.2.x以上的编译器。另外,如果编译过程中遇到了很奇怪的问题无法解决时,可以考虑换一个编
译器版本试试。

下面我们以arm-linux-gcc-3.4.1为例介绍交叉编译环境的建立。

  • 到http://ftp.handhelds.org/projects/toolchain/下载arm-linux-gcc-3.4.1.tar.bz2

$ cd /work/src
$ wget http://ftp.handhelds.org/projects/toolchain/arm-linux-gcc-3.4.1.tar.bz2

  • 解压缩到/usr/local

$ cd /usr/local
$ tar jxf /work/src/arm-linux-gcc-3.4.1.tar.bz2

注意建议不要使用tar的"v"参数,如果解压的文件比较大的话,使用"v"参数与不使用这个参数的解压速度有很大区别。

  • 此时此文件夹下产生usr文件夹,在usr/local文件夹下有我们想要的文件夹arm,它的绝对路径是/usr/local/usr/local/arm,因此使用下面命令把/usr/local/usr/local/arm移到/usr/local/arm

$ mv usr/local/arm ./

  • 交叉编译工具此时存在于/usr/local/arm/3.4.1/bin/

$ ls usr/local/arm/3.4.1/bin/
arm-linux-addr2line arm-linux-cpp arm-linux-gcov arm-linux-ranlib
arm-linux-ar arm-linux-g++ arm-linux-ld arm-linux-readelf
arm-linux-as arm-linux-gcc arm-linux-nm arm-linux-size
arm-linux-c++ arm-linux-gcc-3.4.1 arm-linux-objcopy arm-linux-strings
arm-linux-c++filt arm-linux-gccbug arm-linux-objdump arm-linux-strip

为了方便,我们需要把这个文件夹加到系统变量PATH里面,这样我们就可以像使用系统变量一样使用
这些命令了。编辑~/.bashrc,这个文件是隐藏文件,当用户登入时就会首先执行这个文件,因此我们
可以把设置环境变量的命令写进去。

$ echo “export PATH=$PATH:/usr/local/arm/3.4.1/bin” >> ~/.bashrc
$ source ~/.bashrc

到此为止,我们的交叉编译器就算搞定了,是不是不是想象中的那么难?_

在Windows下交叉编译和调试树莓派软件

本文提供了利用VSCODE+CMAKE在Windows下交叉编译树莓派程序的方法,分别使用本地环境和WSL两种环境两种方式。以及远程调试的方法。

一、Windows下编译树莓派程序

和在Windows下用Mingw编译Windows程序没什么区别,只是生成的东西是树莓派的软件。Host是Windows, Target是ARM Linux。

  1. 安装编译器。
    到这里下载编译器:raspberry编译器下载。

  2. 安装CMAKE

  3. VSCODE 安装CMAKE Tools

  4. 按F1, 输入CMAKE: Quick Start生成CMakeLists.txt

  5. 跨平台编译,要在

    CMakeLists.txt
    

    的最上面加两行指定目标系统和架构,如下(最后一行设置rpath,Windows习惯了喜欢动态库和可执行放在一个文件夹)

    set(CMAKE_SYSTEM_NAME Linux)
    set(CMAKE_SYSTEM_PROCESSOR arm)
    set(CMAKE_BUILD_RPATH "./")
    

二、用WSL来编译树莓派程序

我还有个Respberry Zero,要重新找编译器(疑问,搞不懂官方的系统镜像怎么做到同时适配Zero和4B的?)。
在网上又找到了一个编译器:另一个respberry编译器下载。版本比较新,GCC 10.3.0支持到C++20,我喜欢。

题外话,如果要编译编译器那是一个大工程,可以用这个项目:crosstool-NG。人生苦短,能用就行。

这个编译器是Linux的,编译个树莓派程序还要装个Linux?抓耳挠腮一番突然反应过来,Windows10不就是“最好的Linux发行版”之一吗? ( •̀ .̫ •́ )✧
话不多说,立马打开WSL(我用Ubuntu,装WSL是另一个话题,网上很多,按下不表)。

  1. 把编译器拷进WSL,解压tar -zxvf cross-pi-gcc-10.3.0-0.tar.gz

  2. 手动放到/opt目录,这步只是为了看上去像那么回事一点

  3. 把要编译的源码也拷进来

  4. 安装CMake

  5. 运行VSCODE,连接WSL (需要Remote - WSL扩展)

  6. 在VSCODE里打开源码,提示说要为WSL安装扩展,那就装,直接C/C++ Extension Pack装上齐活。

  7. 不出意外,CMake扫描不到我们下载的跨平台编译器。 按F1, 输入命令

    >cmake: edit user-local cmake kits
    

    ,我们自己加一个。

    注意路径文件写你自己的

    {
        "name": "GCC 10.3.0 armv6l-linux-gnu",
        "compilers": {
          "C": "/opt/cross-pi-gcc-10.3.0-0/bin/arm-linux-gnueabihf-gcc",
          "CXX": "/opt/cross-pi-gcc-10.3.0-0/bin/arm-linux-gnueabihf-g++"
        }
    }
    
  8. 重新启动VSCODE,选择自己加进来的这个编译器。

  9. CMAKE自动开始配置,我的配置完了提示说啥Error: spawn arm-linux-gnueabihf-gcc ENOENT错误之类的云云,无视之。

  10. 可以编译了,复制到ZERO里运行看看吧

三、通过gdbserver远程调试

在VSCODE的Run and Debug中,可以生成launch.json文件,里面这样写:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "remote_debug_demo",
            "type": "cppdbg",
            "request": "launch",
            // 你的程序名,比如我的是demo
            "program": "${workspaceFolder}/build/demo",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}/build/",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "gdb pretty",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            // 这里是跨平台编译器带的GDB
            "miDebuggerPath":"/opt/cross-pi-gcc-10.3.0-0/bin/arm-linux-gnueabihf-gdb",
            // 这里是树莓派的IP地址和gdbserver的端口
            "miDebuggerServerAddress":"192.168.2.226:2000"
        }   
    ]
}
  1. 在树莓派中,安装gdbserver

  2. 程序编译成DEBUG版,并复制到树莓派中,以我的demo程序为例

  3. 执行gdbserver 0.0.0.0:2000 ./demo,启动软件开始调试demo程序。

  4. 在VSCODE中,按F5连接到树莓派调试。

    题外话:我启动时遇到了gdb缺少依赖的情况,可以用ldd arm-linux-gnueabihf-gdb命令查看缺少什么。对照着装就可以。
    我装了sudo apt install libpython2.7 libncurses5后搞定。

基于 MinGW 搭建 Windows 下的交叉编译环境

前言

在搭建交叉编译环境之前,软件的整个工程已经在开发板上直接编译通过。
目标软件是一个基于 Qt 的软件,使用 cmake + gcc 编译,同时需要 boost 等三方库,这些工具和库,之前都是直接在开发板的 Linux 环境中编译的。
本文不详细说明 Qt 和第三方库的编译过程,只是在上述基础上,搭建 Windows 下的交叉编译环境。

环境

硬件

* 主机:Dell XPS 15 9550
* CPU:i7-6700HQ @ 2.60GHz
* GPU 1:Intel(R) HD Graphics 530
* GPU 2:NVIDIA GeForce GTX 960M
* 内存:16GB
* 硬盘:265G SSD + 1TB 机械硬盘
  • 软件
    • 操作系统:Windows 10 教育版

下载安装 MinGW

下载安装工具:http://www.mingw.org/download/installer
运行下载后的可执行程序:mingw-get-setup.exe

选择安装路径 D:\MinGW

在打开的 MinGW Installation Manager 中,选择安装:

  • mingw-developer-toolkit
  • mingw32-base
  • mingw32-gcc-g++
  • msys-base

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yWk2P3h-1680694951420)(https://yunfengbo.github.io/blog/2018/04/26/MinGW-cross-complie/MinGW-cross-complie/1.jpg)]
然后在菜单 Installation 中,选择 Apply Changes

完成后,运行 d:\MinGW\msys\1.0\msys.bat,打开 msys 命令行窗口:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yejp70k2-1680694964153)(null)]

新建一个目录,然后到 Linaro 官网下载交叉编译工具:

  • 目标 64 位系统:gcc-linaro-7.2.1-2017.11-i686-mingw32_aarch64-linux-gnu.tar.xz
  • 目标 32 位系统:gcc-linaro-7.2.1-2017.11-i686-mingw32_arm-linux-gnueabihf.tar.xz

将下载后的交叉编译工具(以下为64位工具,32位类似),复制并解压:

mkdir arm-corss
xz -d gcc-linaro-7.2.1-2017.11-i686-mingw32_aarch64-linux-gnu.tar.xz
tar -xvf gcc-linaro-7.2.1-2017.11-i686-mingw32_aarch64-linux-gnu.tar

export PATH=$PATH:~/arm-corss/gcc-linaro-7.2.1-2017.11-i686-mingw32_aarch64-linux-gnu/bin

将下载后的交叉编译工具(以下为64位工具,32位类似),复制并解压:

mkdir arm-corss
xz -d gcc-linaro-7.2.1-2017.11-i686-mingw32_arm-linux-gnueabihf.tar.xz
tar -xvf gcc-linaro-7.2.1-2017.11-i686-mingw32_arm-linux-gnueabihf.tar

export PATH=$PATH:~/arm-corss/gcc-linaro-7.2.1-2017.11-i686-mingw32_arm-linux-gnueabihf/bin

以下内容,都以 64 位目标系统为例说明。

从最简单的开始

创建一个最简单的程序,保存为 hello.cpp:

#include <iostream>

int main(int argc, char *argv[])
{
    std::cout << "Hello World!" << std::endl;
    
    return 0;
}

在 msys 窗口中编译:

aarch64-linux-gnu-g++ hello.cpp -o hello

将编译好的 hello 文件上传到 ARM 开发板,然后在 ARM 环境中执行命令:

chmod +x hello
./hello

可以看到输出文字为:
Hello World!

复杂一点的

创建一个 OpenGL 程序,保存为 glut_test.cpp:

#include <GL/glut.h>

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glMatrixMode(GL_PROJECTION);
    glOrtho(-5, 5, -5, 5, 5, 15);
    glMatrixMode(GL_MODELVIEW);
    gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);

    return;
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 0, 0);
    glutWireTeapot(3);
    glFlush();

    return;
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitWindowPosition(0, 0);
    glutInitWindowSize(300, 300);
    glutCreateWindow("OpenGL 3D View");
    init();
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

此时,编译上述程序:

aarch64-linux-gnu-g++ glut_test.cpp -lglut -lGL -lGLU -o glut_test

未完……

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文搞懂交叉编译,Windows和Linux的交叉编译 的相关文章

  • MFC中如何获取子菜单?

    我正在尝试获取一个子菜单 以便我可以在显示它之前对其进行更改 所以我创建了一个OnInitMenu 我的窗口的处理程序 我本来计划使用pMenu gt GetMenuItemInfo 获取子菜单 然而 这似乎行不通 为了找到我想要的菜单 我
  • 通过.NET/C#发送传真

    如何在 NET 中发送传真 我们有一个传真服务器 我们需要通过它将文件传真给客户 由于我们有传真服务器 我不认为我必须在我的机器上配置传真调制解调器 对吧 它只会通过传真服务器吗 有没有好的免费 或便宜 传真 API 在我的研究中 我遇到过
  • 为什么不使用 sshrc 中设置的 $PATH?

    我正在尝试在 OS X 服务器上通过 ssh 设置 svn 为了做到这一点 我读到我需要一个包装器来设置 umask 并 在我的例子中 设置存储库根 一种快速而肮脏的方法是重命名 usr bin svnserve并将包装器脚本放置在该位置
  • 当应用程序最小化时隐藏表单

    我有一个主表单和一个状态表单 当我的应用程序中的工作正在进行时 我会显示它们 如果工作完成我就打电话Hide状态表上出现 状态表消失 当我最小化主窗体而等待窗体可见时 就会出现问题 然后两种形式都被隐藏 这就是我想要的 但是 如果工作完成时
  • 如何使用c在Linux中获取当前时间戳(以纳秒为单位)

    我知道我们可以使用clock gettime CLOCK MONOTONIC 我尝试问的问题是 如果我需要以纳秒为单位的时间 从时代来看 这将是一个巨大的数字 例如 自纪元以来的秒数是13438461673 so 13438461673 1
  • Microsoft Visual Studio 10.0\VC\include\io.h 提供了什么?

    我安装了 Visual Studio 2010 它给了我 C 编译器 C Program Files x86 Microsoft Visual Studio 10 0 VC vcvarsall bat 然而 当我尝试构建一个应用程序 一个P
  • 在 C#/VB.NET 或 C++ Win32 中启用/禁用 Aero

    如何在 C NET 或 C Win32 中禁用航空效果 这是我在 C C 中的测试代码 但仅在我的应用程序运行时才有效 include
  • 导出的 DLL 函数未按词法排序?

    嗯 今天我遇到了一个奇怪的事情 我不久前编写了自己的 GetProcAddress 版本 用于从远程进程获取函数地址 显然我花了很多时间阅读 PE 架构来找出解决这个问题的最佳方法 根据 PECOFF v8 规范 我认为这是最新的官方规范
  • 如何使文件自我更新(Native C++)

    我将 Microsoft Visual Studio 2008 与 Windows 目标部署结合使用 我如何使文件 自我更新 我已经完成了 通过网络传输 部分 但是如何使可执行文件重写自身 基本上 我想为还包含自动更新程序的目录编写一个自动
  • Windows 上的 ruby​​ 中出现 SSL 错误

    我收到以下错误 C Users user Desktop folder gt ruby exchange rate rb C Ruby23 x64 lib ruby 2 3 0 net http rb 933 in connect nonb
  • 我应该如何从非 root Debian Linux 守护进程登录?

    我正在编写一个新的守护进程 它将托管在 Debian Linux 上 我发现 var log 具有仅 root 写入权限 因此我的守护进程无法在那里写入日志文件 但是 如果它写入那里 它似乎将获得自动日志轮转 并且也按照用户期望的方式工作
  • 参数无效”设置键“net.core.somaxconn”

    我尝试设置Linux内核 编辑后 etc sysctl conf并执行sysctl p它显示错误 Invalid argument setting key net core somaxconn Linux 发行版 Ubuntu 12 04
  • 是否可以确定哪个键盘发送了按键?

    我有一个 Windows Media Center 遥控器 Windows 将其识别为键盘 当我使用 Windows Media Center 运行多显示器设置并在一个屏幕上播放视频时 遥控器的输入将与常规键盘一起定向到活动窗口 因此 当我
  • 如何获取文件或目录的标准化日期/时间戳。在纯批处理脚本中?

    Windows 命令行中有没有一种方法可以检索标准化文件或目录的日期 时间戳 修改 创建 访问 独立于语言环境格式 例如 ISO8601 http www iso org iso home standards iso8601 htm 我发现
  • 如何使用 Windows API 检索 HD 供应商/序列号

    我说的是physical磁盘驱动器 而不是卷 分区 逻辑驱动器 所以通常建议GetVolumeInformation函数不适用于我的情况 确切地说 我直接使用尚未分区的磁盘 我通过打开它的句柄CreateFile功能 hDisk Creat
  • 调用 close() 后大文件没有立即刷新到磁盘?

    我正在使用 python 脚本创建大文件 超过1GB 实际上有 8 个 在创建它们之后 我必须创建将使用这些文件的进程 该脚本如下所示 This is more complex function but it basically does
  • 使用vim,如何快速刷新正在处理的网页?

    我已经使用 VIM 几个星期了 同时处理各种网络语言 我真的很喜欢它 我发现必须点击或单击浏览器并刷新页面才能看到代码更改的效果 这很麻烦 更烦人的是 因为我使用的是 Virtual Box 而且我倾向于在主机系统上处理 PDF 文件 因此
  • PHP中如何找出特定进程仍在运行

    我正在编写一个脚本 该脚本构建其他脚本的队列 并应该管理它们的启动 管理器脚本应该知道哪个子进程已经完成 因此它可以启动在队列中等待的其他脚本 我添加了一个 echo 获取每个子进程的进程 ID 所以我有我的子进程进程 ID 现在正在使用系
  • Git core.safecrlf 对具有相同行结尾的文件有不同的行为

    我有带有 VS 项目的 Windows 计算机 并且使用 Visual Studio 和 Cygwin 环境中的工具 包括 Git 有时 编辑后我会在文件中得到不同的行结尾 我想要简单的解决方案来检查文件的行尾一致性 然后再将其发送到存储库
  • 无法声明接口:资源繁忙

    我正在使用 USB4Java 低级版本 并且基本上是根据这段代码工作的here http www mets blog com java usb communication usb4java 我在 Ubuntu 中工作 遇到了有关权限的问题

随机推荐

  • 2021-07-11(浙大可视化暑期网上学校)--可视化设计、编码、变换

    大纲 可视化设计 好的可视化 xff08 准则 xff09 xff1a 最少的墨水 最小的空间 传递最多的信息 1 真实度 xff1a 图形实体 xff08 眼见不一定为实 xff09 xff08 1 xff09 谎言因子 xff1a 在实
  • C++ prev()函数用法

    含义 xff1a pre具有前一个的意思 xff0c 该函数可用来获取一个距离指定迭代器 n 个元素的迭代器 具体用法如下图 xff1a include lt bits stdc 43 43 h gt using namespace std
  • js中+的特殊用法:将字符串类型转换为number类型

    当一个字符串全是数字时 xff0c 通过在它前面添加 43 使字符串类型转化为number类型 xff0c 如下图 xff1a 注意 xff1a 只有当字符串是数字时才行 xff0c 正负数都可以 xff0c 也可以带前导零 xff1b 但
  • Vue中的Vuex

    简介 1 组成部分 xff1a xff08 三个对象类型 xff09 Actions xff1a 用来接收从Vue Componts的方法和数值 xff0c 如果需要去调用数值也可以先去调用成功数值后再传给MutationMutation
  • Vue路由

    路由简介 1 简介 xff08 1 xff09 路由就是一组key value的对应关系 xff08 2 xff09 路由要经过路由器的管理 2 路由工作原理简介 xff1a xff08 1 xff09 目的 xff1a 为了实现导航区和展
  • exit的用法

    exit函数的作用 xff1a 是程序正常退出 使用方法 xff1a 1 exit 表示结束当前进程 2 exit xff08 1 xff09 结束当前进程并且返回1 xff1b 3 exit xff08 2 xff09 结束当前进程并且返
  • pat(甲级)1004(dfs)

    1004 Counting Leaves 30 xff08 30 分 xff09 A family hierarchy is usually presented by a pedigree tree Your job is to count
  • Arch Linux 安装指南(ArchISO 2014.02.01 适用)

    1 写在前 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 o 本指南编译自Arch Wiki 新手指南 x
  • 数字华容道有解的条件

    问题 xff1a 有n n的矩阵 xff0c 分别填入1 n m 1 xff0c 和0 xff0c 给出一个矩阵的局势 xff0c 问是否可以将这个局势变为有序的最初矩阵 解法 xff1a xff08 eg xff1a 图1的数字顺序 1
  • 一个简易的招聘网站的数据库设计过程

    1 user表的增删改查及相关功能 1 1 admin下的权限 xff1a 可以查询所有的user信息 xff08 除去密码 xff09 xff1a select user id mobile name gender birth nickn
  • Spring5课程的思维导图

    Spring5课程的思维导图 xff08 来源百知教育 的 孙哥说Spring5的笔记视频 xff0c 外加自己的一点点理解 xff09 知识点都在导图上 xff0c 图有点大 xff0c 加载有点慢 xff0c 这里截一点图放上面 xff
  • Oracle数据库安装记录--Linux系统

    环境准备 Oracle数据库版本 xff1a 19C 系统环境 xff1a Linux系统 centOS7 所需的安装包 xff08 以下安装包都需要 xff09 安装包一 xff1a oracle database preinsta 1
  • 将对象集合具有相同属性的分到一组

    工具说明 将对象集合具有相同属性的分到一组 xff0c 必须保证属性对象在每一个小集合中唯一 比如 xff1a 参数元素一 xff08 与顺序无关 xff09 xff1a 第一个 xff1a 主ID1 从ID1 元素1 第二个 xff1a
  • 基于Verilog键盘的实现

    请实现对4 4矩阵式健盘的按键识别参考书籍 Verilog HDL高级数字设计 由图可知 xff0c 键盘的每一列通过一个上拉电阻 xff0c 接到VCC 在检测有没有按键按下时 xff0c 我们可以 xff0c 先使行线同时为0 xff0
  • /nginx: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No

    在CentOS7下配置Nginx xff0c 但是一致都在报错 报错信息为 xff1a nginx error while loading shared libraries libcrypto so 1 1 cannot open shar
  • 【转载】sprintf的实现

    原文链接 我们已经知道printf 是控制台程序中最常用的函数 xff0c 作用是输入的字符 数字等信息拼成完整的句子并且输出到标准输出设备 显示器 控制台等 xff0c sprintf 函数命名与printf 函数及其相似又有什么作用呢
  • 【程序员读论文】题外篇:怎么读论文

    文章目录 1 如何高效读论文 xff1f 痛苦选择顺序笔记小结讨论 2 如何有针对地高效地阅读一篇学术论文 xff1f 3 一文教你如何快速高效阅读Paper xff08 硕士生版 xff09 前言Paper从哪来Paper怎么读Paper
  • Linux中C语言标准库glibc源码下载

    在这篇文章理清gcc libc glibc libc 43 43 libstdc 43 43 的关系 xff0c 我们大概理解了libc xff0c glibc之间的一些关系 下面我们就开了解一些Linux中C语言标准库glibc源码 在这
  • 50个常用SQL语句

    50个常用SQL语句 Student S Sname Sage Ssex 学生表 S 学号 xff0c 主键 Course C Cname T 课程表 C 课程号 xff0c 主键 SC S C score 成绩表 Teacher T Tn
  • 一文搞懂交叉编译,Windows和Linux的交叉编译

    文章目录 什么是交叉编译为什么要交叉编译工具链的种类 我们应该怎样建立交叉编译环境在Windows下交叉编译和调试树莓派软件一 Windows下编译树莓派程序二 用WSL来编译树莓派程序三 通过gdbserver远程调试 基于 MinGW