Android Studio 3.5.2最小化接入weex 0.28.0实践

目前在尝试使用weex,但是在搭建基础的最小化项目的时候,官方文档描述的相当佛系,导致搭建出来的项目没办法正常运行。

下面我们探讨一下,使用`Android Studio 3.5.2`新建一个项目,实现最小化接入`weex 0.28.0`实践过程。

官方文档要求在项目的`build.gradle` 中增加如下内容:

implementation 'org.apache.weex:sdk:0.28.0@aar'
implementation 'com.alibaba:fastjson:1.2.62'

但是实际上,由于`weex 0.28.0`的调整,以前版本自动引入的`facebook`提供的`JS`引擎js-android,现在被修改为需要手工引入,但是文档没有清晰的指出这个问题,导致运行的时候,会由于找不到`libjsc.so`而导致`WXSDKEngine`初始化失败。

官方提供了一个`download_jsc.gradle`的脚本解决这个问题(这个脚本的功能仅仅是下载`libjsc.so` ),需要在项目的 `build.gradle` 的头部增加这个脚本文件的引用:

apply from: 'https://raw.githubusercontent.com/apache/incubator-weex/release/0.28/android/sdk/buildSrc/download_jsc.gradle'

如果下载不成功,也可从本站下载

apply from: 'https://www.mobibrw.com/wp-content/uploads/2019/11/download_jsc.gradle'

完成后的`build.gradle`中完整内容如下:

apply plugin: 'com.android.application'
apply from: 'https://raw.githubusercontent.com/apache/incubator-weex/release/0.28/android/sdk/buildSrc/download_jsc.gradle'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.mobibrw.weex"
        minSdkVersion 22
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        ndk {
            abiFilters "armeabi","armeabi-v7a", "arm64-v8a", "x86"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'org.apache.weex:sdk:0.28.0@aar'
    implementation 'com.alibaba:fastjson:1.2.62'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

接下来,就是具体的代码部分了,如下,需要自定义一个`Application`类,在`Application`的初始化部分初始化`WXSDKEngine`,代码如下:

package com.mobibrw.weex;

import android.app.Application;
import org.apache.weex.InitConfig;
import org.apache.weex.WXSDKEngine;

public class WeexApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        final InitConfig config = new InitConfig.Builder().build();
        /**
         * 底层的初始化是异步执行的,尤其是初始化JS引擎部分的代码(WXBridgeManager),是相当耗时的
         * 因此,在调用完初始化之后,Activity第一次调用的时候,一定要增加是否已经初始化完成的判断
         * 如果没有完成初始化,适当的增加延迟等待的代码
         **/
        WXSDKEngine.initialize(this, config);
    }

}

接下来,就是具体的`Activity`内容展现代码部分了,代码如下:

package com.mobibrw.weex;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import org.apache.weex.IWXRenderListener;
import org.apache.weex.WXSDKEngine;
import org.apache.weex.WXSDKInstance;
import org.apache.weex.common.WXRenderStrategy;

public class MainActivity extends AppCompatActivity implements IWXRenderListener {

    private WXSDKInstance wXSDKInstance;

    private static final String TAG = "WXSampleTAG";

    private void loadPages() {
        /**
         * bundleUrl source http://dotwe.org/vue/38e202c16bdfefbdb88a8754f975454c
         */
        String pageName = "WXSample";
        String bundleUrl = "http://dotwe.org/raw/dist/38e202c16bdfefbdb88a8754f975454c.bundle.wx";
        wXSDKInstance.renderByUrl(pageName, bundleUrl, null, null, WXRenderStrategy.APPEND_ASYNC);
    }

    private void asyncLoadPages(final View view) {
        /**
         * 此处一定要判断WXSDKEngine是否已经成功初始化了,由于WXSDKEngine底层初始化的库非常多
         * 导致整个的初始化非常的耗时,并且这个初始化是异步执行的,尤其是初始化JS引擎部分的代码(WXBridgeManager)。
         * 因此有非常大的概率导致当第一次使用Week的API的时候,底层还没有完成初始化
         * 导致出现错信息 "degradeToH5|createInstance fail|wx_create_instance_error isJSFrameworkInit==false reInitCount == 1"
         * 这段耗时可以通过在程序启动的时候增加启动等待页面来人性化的忽略这部分耗时。
         **/
        if(!WXSDKEngine.isInitialized()) {
            view.postDelayed(new Runnable() {
                @Override
                public void run() {
                    asyncLoadPages(view);
                }
            }, 1);
        } else {
            loadPages();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final View view = findViewById(R.id.activity_main);

        wXSDKInstance = new WXSDKInstance(this);
        wXSDKInstance.registerRenderListener(this);
        asyncLoadPages(view);
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }

    @Override
    public void onViewCreated(WXSDKInstance instance, View view) {
        setContentView(view);
    }

    @Override
    public void onRenderSuccess(WXSDKInstance instance, int width, int height) {
        Log.i(TAG, "onRenderSuccess");
    }

    @Override
    public void onRefreshSuccess(WXSDKInstance instance, int width, int height) {
        Log.i(TAG, "onRefreshSuccess");
    }

    @Override
    public void onException(WXSDKInstance instance, String errCode, String msg) {
        Log.e(TAG, "onException:" + msg);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityPause();
        }
    }
    @Override
    protected void onStop() {
        super.onStop();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityStop();
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(wXSDKInstance!=null){
            wXSDKInstance.onActivityDestroy();
        }
    }
}

需要注意的是`WXSDKEngine`是异步初始化的,导致在首次调用的时候,可能会因为没有正常初始化而出现异常,因此需要等待初始化完成。

具体的例子项目在这里下载 Weex

鉴于开源项目经常性找不到文件,因此记录下来 http://dotwe.org/raw/dist/38e202c16bdfefbdb88a8754f975454c.bundle.wx 这个文件里面的内容:

// { "framework": "Vue" }

/******/
(function(modules) { // webpackBootstrap
    /******/ // The module cache
    /******/
    var installedModules = {};

    /******/ // The require function
    /******/
    function __webpack_require__(moduleId) {

        /******/ // Check if module is in cache
        /******/
        if (installedModules[moduleId])
        /******/
            return installedModules[moduleId].exports;

        /******/ // Create a new module (and put it into the cache)
        /******/
        var module = installedModules[moduleId] = {
            /******/
            exports: {},
            /******/
            id: moduleId,
            /******/
            loaded: false
                /******/
        };

        /******/ // Execute the module function
        /******/
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

        /******/ // Flag the module as loaded
        /******/
        module.loaded = true;

        /******/ // Return the exports of the module
        /******/
        return module.exports;
        /******/
    }


    /******/ // expose the modules object (__webpack_modules__)
    /******/
    __webpack_require__.m = modules;

    /******/ // expose the module cache
    /******/
    __webpack_require__.c = installedModules;

    /******/ // __webpack_public_path__
    /******/
    __webpack_require__.p = "";

    /******/ // Load entry module and return exports
    /******/
    return __webpack_require__(0);
    /******/
})
/************************************************************************/
/******/
([
    /* 0 */
    /***/
    function(module, exports, __webpack_require__) {

        'use strict';

        var _e202c16bdfefbdb88a8754f975454c = __webpack_require__(1);

        var _e202c16bdfefbdb88a8754f975454c2 = _interopRequireDefault(_e202c16bdfefbdb88a8754f975454c);

        function _interopRequireDefault(obj) {
            return obj && obj.__esModule ? obj : {
                default: obj
            };
        }

        _e202c16bdfefbdb88a8754f975454c2.default.el = '#root';
        new Vue(_e202c16bdfefbdb88a8754f975454c2.default);

        /***/
    },
    /* 1 */
    /***/
    function(module, exports, __webpack_require__) {

        var __vue_exports__, __vue_options__
        var __vue_styles__ = []

        /* styles */
        __vue_styles__.push(__webpack_require__(2))

        /* script */
        __vue_exports__ = __webpack_require__(3)

        /* template */
        var __vue_template__ = __webpack_require__(4)
        __vue_options__ = __vue_exports__ = __vue_exports__ || {}
        if (
            typeof __vue_exports__.default === "object" ||
            typeof __vue_exports__.default === "function"
        ) {
            if (Object.keys(__vue_exports__).some(function(key) {
                    return key !== "default" && key !== "__esModule"
                })) {
                console.error("named exports are not supported in *.vue files.")
            }
            __vue_options__ = __vue_exports__ = __vue_exports__.default
        }
        if (typeof __vue_options__ === "function") {
            __vue_options__ = __vue_options__.options
        }
        __vue_options__.__file = "/usr/src/app/raw/38e202c16bdfefbdb88a8754f975454c.vue"
        __vue_options__.render = __vue_template__.render
        __vue_options__.staticRenderFns = __vue_template__.staticRenderFns
        __vue_options__._scopeId = "data-v-02e1e786"
        __vue_options__.style = __vue_options__.style || {}
        __vue_styles__.forEach(function(module) {
            for (var name in module) {
                __vue_options__.style[name] = module[name]
            }
        })
        if (typeof __register_static_styles__ === "function") {
            __register_static_styles__(__vue_options__._scopeId, __vue_styles__)
        }

        module.exports = __vue_exports__


        /***/
    },
    /* 2 */
    /***/
    function(module, exports) {

        module.exports = {
            "text": {
                "fontSize": 50
            }
        }

        /***/
    },
    /* 3 */
    /***/
    function(module, exports) {

        'use strict';

        Object.defineProperty(exports, "__esModule", {
            value: true
        });
        //
        //
        //
        //
        //
        //
        //
        //
        //
        //

        exports.default = {
            data: function data() {
                return {
                    text: 'Hello World.'
                };
            }
        };

        /***/
    },
    /* 4 */
    /***/
    function(module, exports) {

        module.exports = {
            render: function() {
                var _vm = this;
                var _h = _vm.$createElement;
                var _c = _vm._self._c || _h;
                return _c('div', [_c('text', {
                    staticClass: ["text"]
                }, [_vm._v(_vm._s(_vm.text))])])
            },
            staticRenderFns: []
        }
        module.exports.render._withStripped = true

        /***/
    }
    /******/
]);

参考链接


html数学公式显示库MathJax的使用

MathJax是一个开源的web数学公式渲染器,由JS编写而成。MathJax允许你在你的网页中包含公式,无论是使用LaTeX、MathML或者AsciiMath符号,这些公式都会被javascript处理为HTML、SVG或者MathML符号。

引入CDN

只需要在头部添加下面这句,就可以成功引入CDN

<script type="text/javascript" async
        src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" async>
</script>
内联config说明

官方提供了一个能让我们内联一个配置选项的功能,要想让这个内联配置生效就得放在
CDN引入之前。如下

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    showProcessingMessages: false, //关闭js加载过程信息
    messageStyle: "none", //不显示信息
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
      skipTags: ['script', 'noscript', 'style', 'textarea', 'pre','code', 'a', 'annotation', 'annotation-xml'],
      ignoreClass: 'crayon-.*' // 'crayon-' 开头的类,属于Wordpress代码高亮库,这部分不需要处理,否则会导致显示不正确,这部分是正则式,多条之间用'|'分割    
    },
    'HTML-CSS': {
        showMathMenu: false //禁用右键菜单
    }
  });
  MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
</script>

MathJax 2.x 跟 MathJax 3.x 的配置信息是不同的,这部分的配置转换可以通过MathJax-demos-web中的v2 to v3 Configuration Converter

上面的配置信息,转换后的结果如下:

window.MathJax = {
  tex: {
    inlineMath: [ ['$','$'], ["\\(","\\)"] ],
    displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
  },
  options: {
    skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre','code', 'a', 'annotation', 'annotation-xml'],
    ignoreHtmlClass: 'tex2jax_ignore|crayon-.*', // 'crayon-' 开头的类,属于Wordpress代码高亮库,这部分不需要处理,否则会导致显示不正确,这部分是正则式,多条之间用'|'分割
    processHtmlClass: 'tex2jax_process'
  },
  //禁用右键菜单	
  renderActions: {
    addMenu: [0, '', '']
  }
};

其中MathJax.Hub.Config()里的配置选项是重点,本例表示用来识别行内公式,$来识别行间公式。

书写公式

对应的公式在html文件中写法如下

<body>
${x}^{(2)}\text{=}\begin{bmatrix} 1416\\ 3\\ 2\\ 40 \end{bmatrix}$
</body>
显示效果

WordPress上实现上述功能,最简单的方式是安装 Simple Mathjax 插件即可。

注意目前(2022/03/16)的 MathJax 3.x 还不支持多语言,不支持公式自动换行(automatic line breaking)

参考链接


Compatibility Between SPIR-V Image Formats And Vulkan Formats

SPIR-V Image Format Compatible Vulkan Format

Rgba32f

VK_FORMAT_R32G32B32A32_SFLOAT

Rgba16f

VK_FORMAT_R16G16B16A16_SFLOAT

R32f

VK_FORMAT_R32_SFLOAT

Rgba8

VK_FORMAT_R8G8B8A8_UNORM

Rgba8Snorm

VK_FORMAT_R8G8B8A8_SNORM

Rg32f

VK_FORMAT_R32G32_SFLOAT

Rg16f

VK_FORMAT_R16G16_SFLOAT

R11fG11fB10f

VK_FORMAT_B10G11R11_UFLOAT_PACK32

R16f

VK_FORMAT_R16_SFLOAT

Rgba16

VK_FORMAT_R16G16B16A16_UNORM

Rgb10A2

VK_FORMAT_A2B10G10R10_UNORM_PACK32

Rg16

VK_FORMAT_R16G16_UNORM

Rg8

VK_FORMAT_R8G8_UNORM

R16

VK_FORMAT_R16_UNORM

R8

VK_FORMAT_R8_UNORM

Rgba16Snorm

VK_FORMAT_R16G16B16A16_SNORM

Rg16Snorm

VK_FORMAT_R16G16_SNORM

Rg8Snorm

VK_FORMAT_R8G8_SNORM

R16Snorm

VK_FORMAT_R16_SNORM

R8Snorm

VK_FORMAT_R8_SNORM

Rgba32i

VK_FORMAT_R32G32B32A32_SINT

Rgba16i

VK_FORMAT_R16G16B16A16_SINT

Rgba8i

VK_FORMAT_R8G8B8A8_SINT

R32i

VK_FORMAT_R32_SINT

Rg32i

VK_FORMAT_R32G32_SINT

Rg16i

VK_FORMAT_R16G16_SINT

Rg8i

VK_FORMAT_R8G8_SINT

R16i

VK_FORMAT_R16_SINT

R8i

VK_FORMAT_R8_SINT

Rgba32ui

VK_FORMAT_R32G32B32A32_UINT

Rgba16ui

VK_FORMAT_R16G16B16A16_UINT

Rgba8ui

VK_FORMAT_R8G8B8A8_UINT

R32ui

VK_FORMAT_R32_UINT

Rgb10a2ui

VK_FORMAT_A2B10G10R10_UINT_PACK32

Rg32ui

VK_FORMAT_R32G32_UINT

Rg16ui

VK_FORMAT_R16G16_UINT

Rg8ui

VK_FORMAT_R8G8_UINT

R16ui

VK_FORMAT_R16_UINT

R8ui

VK_FORMAT_R8_UINT

参考链接


Compatibility Between SPIR-V Image Formats And Vulkan Formats

Ubuntu通过apt-get安装指定版本和查询指定软件有多少个版本

一、通过apt-get安装指定版本

$ apt-get install <<package name>>=<<version>>

二、查询指定软件有多少个版本

说明:在Linux用这个查询并不能完全的把所有版本都列举出来,因为每个版本都与系统版本和CPU架构有关,比如一个软件支持Ubuntu系统的16.04的CPU架构为amd64的版本只有1.0和1.2,其余都不支持,所以列举时就只有两款。

列举版本列表:

0、通过网站搜索:

https://packages.ubuntu.com/

1、

$ apt-cache madison <<package name>>

将列出所有来源的版本。如下输出所示:

$ apt-cache madison vim
   vim | 2:7.3.547-1 | http://debian.mirrors.tds.net/debian/ unstable/main amd64 Packages
   vim | 2:7.3.429-2 | http://debian.mirrors.tds.net/debian/ testing/main amd64 Packages
   vim | 2:7.3.429-2 | http://http.us.debian.org/debian/ testing/main amd64 Packages
   vim | 2:7.3.429-2 | http://debian.mirrors.tds.net/debian/ testing/main Sources
   vim | 2:7.3.547-1 | http://debian.mirrors.tds.net/debian/ unstable/main Sources

`madison` 是一个 `apt-cache` 子命令,可以通过 `man apt-cache` 查询更多用法。

2、

$ apt-cache policy <<package name>>

将列出所有来源的版本。信息会比上面详细一点,如下输出所示:

$ apt-cache policy gdb
gdb:
  Installed: 7.7.1-0ubuntu5~14.04.2
  Candidate: 7.7.1-0ubuntu5~14.04.2
  Version table:
 *** 7.7.1-0ubuntu5~14.04.2 0
        500 http://fr.archive.ubuntu.com/ubuntu/ trusty-updates/main amd64 Packages
        100 /var/lib/dpkg/status
     7.7-0ubuntu3 0
        500 http://fr.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        500 http://archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages

`policy` 是一个 `apt-cache` 子命令,可以通过 `man apt-cache`查询更多用法。

3、

$ apt-cache showpkg <<package name>>

4、

$ apt-get install -s <<package-name>>

说明:这个命令只是模拟安装时会安装哪些软件列表,但不会例举出每个软件有多少个版本

5、

$ aptitude versions <<package name>>

参考:https://manpages.debian.org/unstable/aptitude/aptitude.8.en.html

6、

$ apt-show-versions -a <<package name>>

说明:列举出所有版本,且能查看是否已经安装。还可以通过apt-show-versions -u <<package name>>来查询是否有升级版本。

参考:http://manpages.ubuntu.com/manpages/trusty/man1/apt-show-versions.1p.html

7、

$ whohas -d Debian,Ubuntu <<package name>> | tr -s ' ' '\t' | cut -f 1-3 | column -t

8、

$ rmadison -u debian,ubuntu,bpo <<package name>> | cut -d "|" -f 1-3

单个详情:

1、

$ apt-cache show <<package name>>

说明:查询指定包的详情,不管是否已经安装。

2、

$ dpkg -l <<package name>>

说明:效果和上面基本一致,但是结果是列表详情展示,会提示是否已经删除了之后还有依赖包没有删除等。

3、

$ dpkg -s <<package name>>

说明:必须是安装的包才能显示详情。

4、

$ dpkg-query -s <<package name>>

说明:同上,效果一致。

使用技巧:

1、可以在查询后面带上一些参数来实现筛选

$ apt-cache show package | grep Version
$ apt-show-versions | more

参考链接


Ubuntu通过apt-get安装指定版本和查询指定软件有多少个版本

WD MyCloud编译golang/git-lfs

按照How to successfully build packages for WD My Cloud from source中的介绍,搭建完成WDMyCloud的编译环境

整个 `WD MyCloud` 的编译项目,可以直接在树莓派中进行编译。只是编译`4KB`分页(主要用于编译过程)的高版本应用的时候,需要在 `raspbian-wheezy` 系统中进行编译。

在树莓派中编译 `WD MyCloud` 代码的时候,由于都是 `ARM` 环境,因此,不需要 `QEMU` 的介入,以前由于 `QEMU` 导致的问题可以规避。

推荐在树莓派4B版本上搭建编译环境,效果来看,速度还是不错的。

root@debian:~/git-lfs# DEB_BUILD_OPTIONS="nocheck" dpkg-buildpackage -d -b -uc
dpkg-buildpackage: source package git-lfs
dpkg-buildpackage: source version 2.9.0
dpkg-buildpackage: source changed by brian m. carlson <bk2204@github.com>
dpkg-buildpackage: host architecture armhf
 dpkg-source --before-build git-lfs
 debian/rules clean
mkdir -p /tmp/gocache
GO111MODULE=on GOFLAGS=-mod=vendor GOCACHE=/tmp/gocache dh clean --buildsystem=golang --with=golang
   dh_testdir -O--buildsystem=golang
   dh_auto_clean -O--buildsystem=golang
   debian/rules override_dh_clean
make[1]: Entering directory `/root/git-lfs'
rm -f debian/debhelper.log
rm -rf man
dh_clean
make[1]: Leaving directory `/root/git-lfs'
 debian/rules build
mkdir -p /tmp/gocache
GO111MODULE=on GOFLAGS=-mod=vendor GOCACHE=/tmp/gocache dh build --buildsystem=golang --with=golang
   dh_testdir -O--buildsystem=golang
   dh_auto_configure -O--buildsystem=golang
   debian/rules override_dh_auto_build
make[1]: Entering directory `/root/git-lfs'
dh_auto_build
runtime: failed to create new OS thread (have 2 already; errno=22)
throw: runtime.newosproc

goroutine 1 [syscall]:
syscall.Syscall6()
	/build/buildd-golang_1.0.2-1.1-armhf-ygST23/golang-1.0.2/src/pkg/syscall/asm_linux_arm.s:42 +0x8
syscall.setsockopt(0x3, 0x29, 0x1a, 0x10960248, 0x4, ...)
	/usr/lib/go/src/pkg/syscall/zsyscall_linux_arm.go:1101 +0x68
syscall.SetsockoptInt(0x3, 0x29, 0x1a, 0x0, 0x0, ...)
	/usr/lib/go/src/pkg/syscall/syscall_linux.go:478 +0x6c
net.probeIPv6Stack(0xff0000, 0x10960240)
	/usr/lib/go/src/pkg/net/ipsock_posix.go:41 +0x2a0
net.init()
	/usr/lib/go/src/pkg/net/unixsock_posix.go:-2932 +0x7d4
net/http.init()
	/usr/lib/go/src/pkg/net/http/transport.go:753 +0x84
main.init()
	/usr/lib/go/src/cmd/go/vet.go:37 +0xa8

goroutine 2 [runnable]:
created by runtime.main
	/build/buildd-golang_1.0.2-1.1-armhf-ygST23/golang-1.0.2/src/pkg/runtime/proc.c:221
runtime: failed to create new OS thread (have 2 already; errno=22)
throw: runtime.newosproc

goroutine 1 [syscall]:
syscall.Syscall6()
	/build/buildd-golang_1.0.2-1.1-armhf-ygST23/golang-1.0.2/src/pkg/syscall/asm_linux_arm.s:42 +0x8
syscall.setsockopt(0x3, 0x29, 0x1a, 0x10960248, 0x4, ...)
	/usr/lib/go/src/pkg/syscall/zsyscall_linux_arm.go:1101 +0x68
syscall.SetsockoptInt(0x3, 0x29, 0x1a, 0x0, 0x0, ...)
	/usr/lib/go/src/pkg/syscall/syscall_linux.go:478 +0x6c
net.probeIPv6Stack(0xff0000, 0x10960240)
	/usr/lib/go/src/pkg/net/ipsock_posix.go:41 +0x2a0
net.init()
	/usr/lib/go/src/pkg/net/unixsock_posix.go:-2932 +0x7d4
net/http.init()
	/usr/lib/go/src/pkg/net/http/transport.go:753 +0x84
main.init()
	/usr/lib/go/src/cmd/go/vet.go:37 +0xa8

goroutine 2 [runnable]:
created by runtime.main
	/build/buildd-golang_1.0.2-1.1-armhf-ygST23/golang-1.0.2/src/pkg/runtime/proc.c:221
dh_auto_build: go install -v returned exit code 2
make[1]: *** [override_dh_auto_build] Error 2
make[1]: Leaving directory `/root/git-lfs'
make: *** [build] Error 2
dpkg-buildpackage: error: debian/rules build gave error exit status 2

这个问题产生的原因是在`qemu`中创建线程/进程的时候,要求增加`CLONE_SYSVSEM`标志,否则会出现异常。 `go`在创建线程/进程的时候,没有指定这个标记。解决方法就是修改`src/pkg/runtime/os_linux.c`中的`void runtime·newosproc(M *mp, void *stk)`函数,在`flag`中增加`CLONE_SYSVSEM`标志。

这个问题解决起来比较复杂,我们在`x86`下面直接进行交叉编译的时候,是没办法通过编译的,我们可以通过树莓派下进行编译。树莓派使用`2015-05-05-raspbian-wheezy`版本的镜像来进行编译。

树莓派这个版本的系统问题在于  `wheezy`  的源已经被移动地址,因此更新安装软件的时候会报告 `404`  错误,我们需要手工修改一下源地址。

$ sed -i "s/wheezy/oldoldstable/g" /etc/apt/source.list

安装编译依赖

$ sudo apt-get update

$ sudo apt-get install vim

$ sudo apt-get install devscripts

下载并编译代码

$ wget http://security.debian.org/debian-security/pool/updates/main/g/golang/golang_1.3.3.orig.tar.gz

# 也可本站下载 wget https://www.mobibrw.com/wp-content/uploads/2019/11/golang_1.3.3.orig_.tar.gz -O golang_1.3.3.orig.tar.gz

$ mkdir golang_1.3.3

$ tar xvf golang_1.3.3.orig.tar.gz -C golang_1.3.3

$ cd golang_1.3.3/go 

$ wget http://security.debian.org/debian-security/pool/updates/main/g/golang/golang_1.3.3-1+deb8u2.debian.tar.xz

# 也可本站下载 wget https://www.mobibrw.com/wp-content/uploads/2019/11/golang_1.3.3-1deb8u2.debian.tar.xz

$ tar xvf golang_1.3.3-1*.debian.tar.xz

# BUG `runtime: failed to create new OS thread (have 2 already; errno=22)`
$ sed -i "s/| CLONE_THREAD/| CLONE_THREAD | CLONE_SYSVSEM/g" src/pkg/runtime/os_linux.c

$ export GOARCH=arm

$ export GOOS=linux

$ DEB_BUILD_OPTIONS="nocheck" dpkg-buildpackage -d -b -uc

完成之后,拷贝到编译环境中并执行安装

$ dpkg -i golang-src_1.3.3-1*_armhf.deb

$ dpkg -i golang-go-linux-arm_1.3.3-1*_armhf.deb

$ dpkg -i golang-go_1.3.3-1*_armhf.deb

$ dpkg -i golang-doc_1.3.3-1*_all.deb

继续编译,报告如下错误信息:

root@debian:~/git-lfs# DEB_BUILD_OPTIONS="nocheck" dpkg-buildpackage -d -b -uc
dpkg-buildpackage: source package git-lfs
dpkg-buildpackage: source version 2.9.0
dpkg-buildpackage: source changed by brian m. carlson <bk2204@github.com>
dpkg-buildpackage: host architecture armhf
 dpkg-source --before-build git-lfs
 debian/rules clean
mkdir -p /tmp/gocache
GO111MODULE=on GOFLAGS=-mod=vendor GOCACHE=/tmp/gocache dh clean --buildsystem=golang --with=golang
   dh_testdir -O--buildsystem=golang
   dh_auto_clean -O--buildsystem=golang
   debian/rules override_dh_clean
make[1]: Entering directory `/root/git-lfs'
rm -f debian/debhelper.log
rm -rf man
dh_clean
make[1]: Leaving directory `/root/git-lfs'
 debian/rules build
mkdir -p /tmp/gocache
GO111MODULE=on GOFLAGS=-mod=vendor GOCACHE=/tmp/gocache dh build --buildsystem=golang --with=golang
   dh_testdir -O--buildsystem=golang
   dh_auto_configure -O--buildsystem=golang
   debian/rules override_dh_auto_build
make[1]: Entering directory `/root/git-lfs'
dh_auto_build
fatal error: rt_sigaction failure

runtime stack:
runtime.throw(0x51f24d)
	/usr/lib/go/src/pkg/runtime/panic.c:520 +0x5c
runtime.setsig(0x40, 0x7d5ec, 0x523901)
	/usr/lib/go/src/pkg/runtime/os_linux.c:309 +0xbc
runtime.initsig()
	/usr/lib/go/src/pkg/runtime/signal_unix.c:39 +0x94
runtime.mstart()
	/usr/lib/go/src/pkg/runtime/proc.c:621 +0x80

goroutine 16 [runnable]:
runtime.main()
	/usr/lib/go/src/pkg/runtime/proc.c:207
runtime.goexit()
	/usr/lib/go/src/pkg/runtime/proc.c:1445
fatal error: rt_sigaction failure

runtime stack:
runtime.throw(0x51f24d)
	/usr/lib/go/src/pkg/runtime/panic.c:520 +0x5c
runtime.setsig(0x40, 0x7d5ec, 0x523901)
	/usr/lib/go/src/pkg/runtime/os_linux.c:309 +0xbc
runtime.initsig()
	/usr/lib/go/src/pkg/runtime/signal_unix.c:39 +0x94
runtime.mstart()
	/usr/lib/go/src/pkg/runtime/proc.c:621 +0x80

goroutine 16 [runnable]:
runtime.main()
	/usr/lib/go/src/pkg/runtime/proc.c:207
runtime.goexit()
	/usr/lib/go/src/pkg/runtime/proc.c:1445
dh_auto_build: go install -v returned exit code 2
make[1]: *** [override_dh_auto_build] Error 2
make[1]: Leaving directory `/root/git-lfs'
make: *** [build] Error 2
dpkg-buildpackage: error: debian/rules build gave error exit status 2

这个问题产生的原因是在`qemu`中无法处理编号为 64 的信号(`Qemu rejects rt_sigaction of SIGRTMAX (64).`),我们需要忽略这个信号。解决方法就是修改`src/pkg/runtime/os_linux.c`中的`void
runtime·setsig(int32 i, GoSighandler *fn, bool restart)`函数,忽略这个信号。

# BUG `fatal error: rt_sigaction failure`
$ sed -i "s/runtime·rt_sigaction(i, \&sa, nil, sizeof(sa.sa_mask)) != 0/runtime·rt_sigaction(i, \&sa, nil, sizeof(sa.sa_mask)) != 0 \&\& i != 64/g" src/pkg/runtime/os_linux.c

$ export GOARCH=arm 

$ export GOOS=linux

$ DEB_BUILD_OPTIONS="nocheck" dpkg-buildpackage -d -b -uc

完成之后,拷贝到编译环境中并执行安装

$ dpkg -i golang-src_1.3.3-1*_armhf.deb

$ dpkg -i golang-doc_1.3.3-1*_all.deb

$ dpkg -i golang-go-linux-arm_1.3.3-1*_armhf.deb

$ dpkg -i golang-go_1.3.3-1*_armhf.deb

编译环境安装完成之后,可以成功编译`golang-1.3.3`,中途可能会失败,失败之后,重新编译可以通过。

编译 `golang-1.4` ,由于 `golang-1.4` 的特殊性,任何高于 `golang-1.4` 版本的 `golang` ,都需要 `golang-1.4` 的编译环境才能开始编译安装!
我们依旧需要在树莓派环境中 `raspbian-wheezy` && `WD MyCloud` 编译,如下:

$ git clone https://salsa.debian.org/go-team/compiler/golang.git -b debian/2%1.4.3-3	 	 

# 也可下载一份拷贝 wget https://salsa.debian.org/go-team/compiler/golang/-/archive/debian/2%251.4.3-3/golang-debian-2%251.4.3-3.tar.gz	 	 
# 也可本站下载一份代码拷贝 wget https://www.mobibrw.com/wp-content/uploads/2019/11/golang-debian-21.4.3-3.tar.gz -O golang-debian-2%251.4.3-3.tar.gz	 	 
# tar xvf golang-debian-2%1.4.3-3.tar.gz	 	 
# mv golang-debian-2%1.4.3-3 golang	 	 

$ cd golang	 	 

# BUG `fatal error: rt_sigaction failure` 	 	 
$ sed -i "s/runtime·rt_sigaction(i, \&sa, nil, sizeof(sa.sa_mask)) != 0/runtime·rt_sigaction(i, \&sa, nil, sizeof(sa.sa_mask)) != 0 \&\& i != 64/g" src/runtime/os_linux.c	 	 

# BUG `runtime: failed to create new OS thread (have 2 already; errno=22)`	 	 
$ sed -i "s/| CLONE_THREAD/| CLONE_THREAD | CLONE_SYSVSEM/g" src/runtime/os_linux.c	 	 

# 如果使用 go 1.4.3 编译 go 1.4.3 可能会报告如下三个错误,如果使用 go 1.3.3 编译 go 1.4.3不会出现错误	 	 
#--- FAIL: TestParseInLocation (0.02s)	 	 
# format_test.go:202: ParseInLocation(Feb 01 2013 AST, Baghdad) = 2013-02-01 00:00:00 +0000 AST, want 2013-02-01 00:00:00 +0300 +03	 	 
#--- FAIL: TestLoadFixed (0.00s)	 	 
# time_test.go:929: Now().In(loc).Zone() = "-01", -3600, want "GMT+1", -36	 	 
$ rm -rf src/time/format_test.go	 	 

# time_test.go:929: Now().In(loc).Zone() = "-01", -3600, want "GMT+1", -36	 	 
$ rm -rf src/time/time_test.go	 	 

# file_test.go:121: WriteTo failed: write ip: bad address	 	 
$ rm -rf src/net/file_test.go	 	 

$ export GOARCH=arm
	 	 
$ export GOOS=linux 	 	 
 	 	 
$ DEB_BUILD_OPTIONS="nocheck" dpkg-buildpackage -d -b -uc

完成之后,拷贝到编译环境中并执行安装

$ dpkg -i golang-src_1.4.3-3_armhf.deb	 	 

$ dpkg -i golang-go_1.4.3-3_armhf.deb	 	 

$ dpkg -i golang-doc_1.4.3-3_all.deb	 	 

$ dpkg -i golang-go-linux-arm_1.4.3-3_armhf.deb	 	 

$ dpkg -i golang_1.4.3-3_all.deb

我们需要在 `golang 1.4.3` 环境中继续编译,可以在 `golang 1.3.3` 中运行:

$ cd ~/wdmc-build/64k-wheezy
 
$ sudo chroot build
 
$ mount -t proc none /proc
$ mount -t devtmpfs none /dev
$ mount -t devpts none /dev/pts
 
$ export DEBIAN_FRONTEND=noninteractive
$ export DEBCONF_NONINTERACTIVE_SEEN=true
$ export LC_ALL=C
$ export LANGUAGE=C
$ export LANG=C
$ export DEB_CFLAGS_APPEND='-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE'
$ export DEB_BUILD_OPTIONS=nocheck

$ cd root

$ git clone https://github.com/git-lfs/git-lfs.git

# 或者本站下载一份拷贝 wget https://www.mobibrw.com/wp-content/uploads/2019/11/git-lfs.zip

$ git checkout v1.2.1

$ DEB_BUILD_OPTIONS="nocheck" dpkg-buildpackage -d -b -uc

可以本站下载:
golang_1.3.3-1deb8u2.dsc
golang_1.3.3-1+deb8u2.debian.tar.xz
golang_1.3.3.orig.tar.gz
修改完`BUG`之后编译好的 golang_1.3.3-1.deb(4KB分页)/golang_1.4.3-3.deb(4KB分页)用于编译环境使用,不能在`WD MyCloud`上使用。

参考链接


树莓派国内源

树莓派官方源列表:http://www.raspbian.org/RaspbianMirrors

一下是国内部分:

Asia China Tsinghua University Network Administrators http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/

Unreachable as of 15-may-2015

Asia China Dalian Neusoft University of Information http://mirrors.neusoft.edu.cn/raspbian/raspbian  
Asia China Cohesion Network Security Studio (CNSS)

http://raspbian.cnssuestc.org/raspbian/ 
rsync://raspbian.cnssuestc.org/raspbian

 
Asia China Unique Studio of Huazhong University of Science and Technology

(http|rsync)://mirrors.hustunique.com/raspbian/raspbian

 
Asia China University of Science and Technology of China

(http|rsync)://mirrors.ustc.edu.cn/raspbian/raspbian/

 
Asia China SUN YAT-SEN University http://mirror.sysu.edu.cn/raspbian/  
Asia China Zhejiang University http://mirrors.zju.edu.cn/raspbian/raspbian/  
Asia China Open Source Software Association of Chinese Academy of Sciences http://mirrors.opencas.cn/raspbian/raspbian/  
Asia China Chongqing University http://mirrors.cqu.edu.cn/Raspbian/raspbian/  

重庆大学树莓派源:

wheezy:

deb http://mirrors.cqu.edu.cn/Raspbian/raspbian wheezy main contrib non-free rpi
deb-src http://mirrors.cqu.edu.cn/Raspbian/raspbian/ wheezy main contrib non-free rpi

jessie:

deb http://mirrors.cqu.edu.cn/Raspbian/raspbian jessie main contrib non-free rpi
deb-src http://mirrors.cqu.edu.cn/Raspbian/raspbian/ jessie main contrib non-free rpi

中国科技大学树莓派源:

jessie:

deb http://mirrors.ustc.edu.cn/raspbian/raspbian jessie main contrib non-free rpi

浙江大学

deb http://mirrors.zju.edu.cn/raspbian/raspbian/ wheezy main contrib non-free rpi
deb-src http://mirrors.zju.edu.cn/raspbian/raspbian/ wheezy main contrib non-free rpi

参考链接


树莓派国内源