android源码编译go语言-Android编译器和编译工具编译器

“这是我参加11月更新挑战赛的第四天,详情请参阅:2021年最后更新挑战赛。”

我们已经习惯了IDE以及各种现成的编译工具为我们提供了便捷的编译方式。 我们很少关心编译过程和编译工具的原理。 然而,工具越中间隐藏细节就越多。 这样,当编译遇到问题时,我们无法定位,遇到复杂项目(尤其是不能使用IDE的跨平台项目)时不知如何下手。 所以我打算写两篇关于编译器和编译工具的文章。 本文首先介绍编译工具。

主要从事Android开发,本文主要介绍Android和iOS使用的编程语言和编译器。

Java/Kotlin/Groovy

这三种编程语言基于Java虚拟机。 由于JVM的存在,Java既是编译型语言,又是解释型语言。 如果你把 JVM 看作一个操作系统,它就是一种编译语言; 从数学操作系统的角度来看,它是一种解释性语言。 JVM 负责将编译后的 .class 解释为最终 CPU 可以理解二进制字节。 它为了跨平台实现而牺牲了效率

Java编译工具

我们先从最简单的HelloWorld开始

public class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello, World!");
    }
}

将其命名为 HelloWorld.java。 还记得Java分别为我们提供了编译工具javac执行工具java吗? 我们使用javac来编译:

javac HelloWrold.java

我们看到统计目录生成了HelloWorld.class和HelloWorld.java。 我们继续执行class文件

qingkouwei:~/javaLinux/w1$ java HelloWorld.class
Error: Could not find or load main class HelloWorld.class

报告错误。 我们来回忆一下java的参数传入的是main函数所在的类名,而不是类文件; java会根据类名手动查找class文件。 我们改成java HelloWorld就可以成功看到输出结果了。

使用包名编译类

上面的反例太简单了。 让我们通过添加名称再试一次:

package com.qingkouwei.demo;
public class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello, World!");
    }
}

使用javac编译后,在当前目录生成HelloWorld.class。 运行java HelloWorld后,报错:

Error: Could not find or load main class com.qingkouwei.demo.HelloWorld

这里的包名需要和文件路径对应创建com/qingkouwei/demo目录,放入HelloWorld.class,执行java com.qingkouwei.demo.HelloWorld成功输出:

Hello, World!

这里提出两点:

添加了包名,因此类名也发生了变化。 执行时必须采用包名+类名的形式。 Java会根据包名映射出目录结构,并在目录中搜索从类路径中查找类文件。 由于默认的类路径是当前目录,所以com.qingkouwei.demo.HelloWorld必须存放在./com/qingkouwei/demo/下。

我们还可以使用javac命令的-d参数来指定编译路径:

qingkouwei@mac javac -d . HelloWorld.java 
qingkouwei@mac ls
com  HelloWorld.java
qingkouwei@mac java com.qingkouwei.demo.HelloWorld
Hello, World!

编译具有依赖关系的类

我们将复制Hello World的方法封装成一个Hello鞋工厂类HelloFactory:

package com.qingkouwei.demo;
public class HelloFactory{
    public void printHello(String name){
        System.out.println("Hello, " + name + "!");
    }
}

HelloWorld 调用此方法:

package com.qingkouwei.demo;
public class HelloWorld{
    public static void main(String[] args){
        HelloFactory factory = new HelloFactory();
        factory.printHello("World");
    }
}

这样,HelloWorld就依赖于HelloFactory了。 我们首先编译HelloFactory.java,然后编译HelloWorld.java:

qingkouwei@mac javac -d . HelloFactory.java 
qingkouwei@mac javac -d . HelloWorld.java 
qingkouwei@mac ls
com  HelloFactory.java  HelloWorld.java
qingkouwei@mac java com.qingkouwei.demo.HelloWorld
Hello, World!

如果改变编译顺序会怎样:

qingkouwei@mac javac -d . HelloWorld.java 
HelloWorld.java:4: error: cannot find symbol
        HelloFactory service = new HelloFactory();
        ^
  symbol:   class HelloFactory
  location: class HelloWorld
HelloWorld.java:4: error: cannot find symbol
        HelloFactory service = new HelloFactory();
                                   ^
  symbol:   class HelloFactory
  location: class HelloWorld
2 errors

如果我们需要在编译过程中自动管理依赖关系,成本就太高了。 当项目的复杂性增加时,它几乎无法维护。 我们将同时将两个 java 文件传递​​给 javac:

qingkouwei@mac javac -d . HelloWorld.java HelloFactory.java 
qingkouwei@mac ls
com  HelloFactory.java  HelloWorld.java
qingkouwei@mac  java com.qingkouwei.demo.HelloWorld
Hello, World!

javac 可以手动管理依赖关系。

javac命令总结

javac的句型如下:

javac [ options ] [ sourcefiles ] [ classes] [ @argfiles ]

options:是一些选项,比如-cp、-dsourcefiles:是编译好的java文件,比如HelloWorld.java,可以有多个,用空格分隔classes:用来处理注解。 @argfiles 是包含选项或java文件列表的文件路径,以@符号Kotlin开头

Kotlin 是一种运行在 Java 虚拟机上的静态类型编程语言。 它被称为Android世界的Swift。 它由 JetBrains 设计、开发和开源。 Kotlin 可以编译成 Java 字节码或 JavaScript,使其可以轻松地在没有 JVM 的设备上运行。 在 Google I/O 2017 上,Google 宣布 Kotlin 成为 Android 的官方开发语言。 当它运行在JVM中时,看起来和Java是一样的。 很多东西都是相似的,只是在句型上做了一些改进

Kotlin 命令行编译简介

Kotlin命令行编译工具下载地址github.com/JetBrains/k...bin目录添加到系统环境变量中。 bin 目录包含编译和运行 Kotlin 所需的脚本。 Mac上可以直接使用brew install kotlin安装

创建 helloworld.kt 文件:

fun main(args: Array<String>) {
    println("Hello, World!")
}

使用 Kotlin 编译器编译应用程序

kotlinc helloworld.kt -include-runtime -d hello.jar

您可以通过 kotlinc -help 查看支持的编译选项。

跑步

java -jar hello.jar
Hello, World!

kotlinc 具有与 javac 类似功能

格罗维

Groovy 是一种基于 JVM Java 虚拟机的敏捷开发语言。 它结合了 Python、Ruby 和 Smalltalk 的许多强大功能。 Groovy 代码可以很好地与 Java 代码集成,也可以用来扩展现有代码。 由于 Groovy 运行在 JVM 上,因此它还可以使用用其他非 Java 语言编写的库。 具体用途不再展开

C/C++

Linux上主流的C/C++编译器是GCCclang

海湾合作委员

GCC 是 GNU(Gnu's Not Unix)编译器集合(GCC)。 它是一组编程语言编译器。 它是根据 GPL 和 LGPL 许可证发布免费软件。 它也是GNU项目的关键部分和GNU工具。 链条的主要组成部分之一。 GCC(尤其是C语言编译器)通常被认为是跨平台编译器的事实上的标准。 由 Richard Matthew Stallman 于 1985 年开始开发android源码编译go语言,现在由自由软件基金会维护。 GCC最初是用C开发的,后来由于LLVM和Clang的兴起,更快地将开发语言转换为C++。

gcc/g++进行编译工作时,总共需要4步:

预处理,生成.i文件【预处理器cpp】将预处理后的文件转换为汇编语言,生成文件.s【编译器egcs】将汇编变成目标代码(机器码),生成.o文件【汇编器as】连接目标代码,生成可执行程序 [linker ld] gcc 编译命令和示例

创建主文件:

#include 
int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, World!n");
    return 0;
}

预处理:gcc -E hello.c>pianoapan.txt,-E只激活预处理,不生成文件。 它需要重定向到输出文件。 生成汇编: gcc -S hello.c -S 只激活预处理和编译,也就是说将文件编译成汇编代码。 编译:gcc -c hello.c,-c只激活预处理、编译、汇编,即只将程序变成obj文件,并连接:gcc -o hello hello.c,将其编译成可用图书馆一步到位。 -o 指定目标名称。 默认情况下,gcc编译的文件是a.out。

gcc命令常用选项:

选项说明

-ansi

仅支持 ANSI 标准 C 语法。 该选项将严格禁用某些 GNU C 功能,例如 asmtypeof 关键字。

-C

仅编译并生成目标文件。

-DMACRO

使用字符串“1”定义 MACRO 宏。

-DMACRO=DEFN

使用字符串“DEFN”定义 MACRO 宏。

-E

只需运行 C 预编译器即可。

-G

生成调试信息。 GNU 调试器可以使用此信息。

-目录

指定附加头文件搜索路径DIRECTORY。

-L目录

指定附加库搜索路径 DIRECTORY。

-l库

连接时搜索指定的函数库LIBRARY。

-m486

486 的代码优化

-o文件

生成指定的输出文件。 生成可执行文件时使用。

-O0

不执行任何优化

-O或-O1

优化生成的代码。

-氧气

高级优化。

-O3

比 -O2 进一步优化,包括内联函数。

-共享

生成共享对象文件。 通常在构建共享库时使用。

-静止

禁止共享连接。

-UMACRO

取消定义 MACRO 宏。

-w

不会生成警告消息

-墙

生成所有警告消息。

Clang:是 C、C++、Objective-C 和 Objective-C++ 编程语言的编译器后端。 它使用低级虚拟机(LLVM)作为其前端。 其目标是提供 GNU 编译器套件 (GCC) 的替代品。 作者是 Chris Lattner,在 Apple 的赞助下开发,源代码获得类似 BSD 的伊利诺伊大学厄巴纳-香槟分校开源许可证授权。 Clang 主要用 C++ 编写。

上面提到了LLVM。 LLVM是一个架构编译器的框架系统。 它是用 C++ 编译的,用于优化用任何编程语言编译的程序的编译时、链接时和运行时。 运行时(run-time)和空闲时间(idle-time)仍然对开发人员开放,并且与现有脚本兼容。 虽然clang是LLVM项目的子项目,但它是基于LLVM架构的C/C++/Objective-C编译器后端。

clang 编译命令

不带选项编译链接的用法:#clang hello.c 功能:预处理、汇编、编译、链接hello.c,生成可执行文件。 这里没有指定输出文件,默认输出是a.out。 编译成功后可以看到生成了a.out文件。 在命令行输入./a.out即可执行程序。 ./表示当前目录下,a.out是可执行程序文件名。

选项-o用法:#clang hello.c -o hello功能:预处理、汇编、编译、链接hello.c,生成可执行文件hello.c。 -o 选项用于指定输出文件的文件名。 输入./hello 执行程序。

选项-E用法:#clang -E hello.c -o hello.i 功能:预处理hello.c并输出hello.i文件。

选项-S用法:#clang -S hello.i 功能:将预处理输出文件hello.i组装成hello.s文件。

选项-c用法:#clang -c hello.s 功能:编译汇编输出文件hello.s,输出hello.o文件。

不带选项的链接用法:#clang hello.o -o hello 功能:将编译后的输出文件hello.o链接成最终的可执行文件hello。 输入./hello 执行程序。

如果想直接运行hello,需要将hello复制到/usr/bin目录下。

选项-O用法:#clang -O1 hello.c -o hello 功能:使用编译优化级别1来编译程序。级别为1~3。 级别越高,优化效果越好,但编译时间越长。 输入./hello 执行程序。

8.使用C++ std库编译程序

用法:#clang hello.cpp -o hello -l std c++

功能:编译并链接hello.cpp为测试可执行文件。 -l std c++ 指定链接std c++ 库。

我们可以看到clang和gcc的编译选项是类似的。

NDK

在Android开发中,我们使用NDK工具,通常使用ndk-build来跨平台编译Android c/c++库。 ndk-build是一个什么样的编译工具?

让我们检查一下 ndk-build 文件:

$ cat ndk-build
#!/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
$DIR/build/ndk-build "$@"%

我发现ndk-build只是一个指向/build/ndk-build的脚本。 经过检查,发现/build/ndk-build也是一个脚本:

$ cat build/ndk-build
#!/bin/bash
...
# Check that we have 64-bit binaries on 64-bit system, otherwise fallback
# on 32-bit ones. This gives us more freedom in packaging the NDK.
LOG_MESSAGE=
if [ $HOST_ARCH = x86_64 ]; then
  if [ ! -d $ANDROID_NDK_ROOT/prebuilt/$HOST_TAG ]; then
    HOST_ARCH=x86
    LOG_MESSAGE="(no 64-bit prebuilt binaries detected)"
  fi
fi
...
    get_build_var ()
    {
        local VAR=$1
        local FLAGS=`gen_flags`
        $GNUMAKE --no-print-dir -f $PROGDIR/core/build-local.mk $FLAGS DUMP_${VAR} | tail -1
    }
   ...
    APP_ABIS=`get_build_var APP_ABI`
    for ABI in $APP_ABIS; do
        perl ${LLVM_TOOLCHAIN_PREFIX}scan-build 
            --use-cc $ANALYZER_CC 
            --use-c++ $ANALYZER_CXX 
            --status-bugs 
            $ANALYZER_OUT_FLAG 
            $GNUMAKE -f $PROGDIR/core/build-local.mk "$@" APP_ABI=$ABI
    done
else
    $GNUMAKE -O -f $PROGDIR/core/build-local.mk "$@"
fi

我们看到最终效果就是GNUMAKE变量。 我们看到GNUMAKE=$ANDROID_NDK_ROOT/prebuilt/$HOST_TAG/bin/make,所以无论是ndk-build项目还是cmake项目,最终都只是通过make编译工具来调用具体的编译器。 编译。

r8c 中添加了 Clang 3.1 编译器。 在 NDK r12 中,ndk-build 建议使用 clang 编译器。 在 r13b 中,不再支持 gcc。 NDK_TOOLCHAIN_VERSION 默认使用 clang。 在 r14b 中,gcc 已被弃用。 使用gcc通过-D_ANDROID_API_=$ API指定特定的API。 在r18b中,删除了gcc、gnustl、gabi++、stlport等。具体NDK修订历史参考官网developer.android.com/ndk/downloa...

总而言之,ndk是一个用于c/c++代码跨平台编译的工具集合。 它提供了三种形式的编译代码:

ndk-buildCMake 基于 Make 的独立工具链android源码编译go语言,用于与其他构建系统集成或与基于配置的项目一起使用。

最终它仍然使用GCC/Clang编译器。

Dart 是一种针对客户端优化的编程语言,用于跨所有平台构建快速应用程序。 主要用于微软已经退出的跨平台框架Flutter。 Dart编译特点

即时编译。 代码编译在应用运行的同时进行,给Flutter带来快速的开发体验。 它具有亚秒级热重载(Hot Reloading)功能。 运行前提前编译。 将代码库直接编译为本机 ARM 指令。 为您的应用程序带来快速的启动速度和可预测性能。 Dart编译工具使用

从官网下载编译工具 dart.dev/tools/sdk/a... 解压并配置环境变量后,可以通过 dart --version 查看版本

使用 dart2native 构建和部署命令行程序。 我们想要的 main.dart 源文件:

main(){ 
  print'Hello World'); 
}

使用命令 dart2native main.dart -o hello 编译成可执行文件。

OC/SwiftOC

Apple 使用 Xcode 来学习编译 Objective-C 编程语言。 XCode 的默认编译器是 clang。

准备代码main.m

#import 
int main(int argc, const char * argv[])
{
@autoreleasepool
{
NSLog(@"Hello, World!");
}
return 0;
}

使用命令 clang -fobjc-arc -framework Foundation main.m -o HelloWorld。 编译完成后,可以运行:./hello。 注意

迅速

Swift 是一种开源编程语言,支持多种编程范式并可编译。 它由Apple于2014年WWDC(苹果开发者大会)上发布,用于开发iOS、OS X和watchOS应用程序。 Swift 结合了 C 和 Objective-C 的优点,没有 C 兼容性限制。 Swift 在 Mac OS 和 iOS 平台上可以使用与 Objective-C 相同的运行环境

Swift的开发工具一直是xcode。 我们使用 xcrun swift -emit-executable -sdk $(xcrun --show-sdk-path --sdk macosx) example.swift 在命令行编译 swift 程序。

总结

本文主要介绍移动端相关的编译工具。 它们都是基础入门工具,但是它们将帮助我们将来面对复杂的小项目,尤其是一些跨平台的C/C++项目。 一份代码一份脚本编译所有平台程序都需要我们熟练掌握这个编译工具。

参考

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 android源码编译go语言-Android编译器和编译工具编译器 https://www.wkzy.net/game/201656.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务