使用SSH Key访问服务器

1. 配置

生成的 SSH Key 默认存储在 ~/.ssh 目录下,可以使用 ls ~/.ssh 查看之前是否已经生成过 SSH Key,如果提示 No such file or directory 可以使用如下指令用于生成 SSH Key:

ssh-keygen

接着会询问保存文件的位置以及是否要设定 passphrase,如果设定了 passsphrase 那么每次使用该 SSH Key 的时候都需要输入这个 passsphrase,可以根据自己对安全性的需求设定,空白表示不设定。

如果采用默认的设置,那么会在 ~/.ssh 路径下生成两个 Key,一个私钥 id_rsa ,另一个公钥 id_rsa.pub,私钥需要好好保管。

2. 使用 ssh-copy-id

如果操作系统中有 ssh-copy-id,那么可以直接使用以下命令设置:

ssh-copy-id -i ~/.ssh/id_rsa.pub username@server
  • username:连接服务器的用户名
  • server:服务器的域名或者 ip 地址
  • ~/.ssh/id_rsa.pub:默认的公钥地址,如果修改过 SSH Key 存储地址,请填写对应地址

3. 复制公钥到服务器的 authorized_keys 中

ssh username@server 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys' < ~/.ssh/id_rsa.pub

上述命令用于在远程服务器上创建 ~/.ssh 文件夹并用本机的公钥创建服务器上的 ~/.ssh/authorized_keys 文件,接着设置权限:

ssh username@server 'chmod 700 -R ~/.ssh && chmod 600 ~/.ssh/authorized_keys'

4. 验证

经过上述的配置之后,可以再次进行 SSH 连接验证配置是否生效:

ssh username@server

如果不需要输入密码就能够连接服务器,说明设置生效。

参考链接


使用 SSH Key 访问服务器

Ubuntu 22.04 (x64)树莓派4B(Raspberry Pi 4B)源代码编译

树莓派上的操作


树莓派使用的系统是通过 Raspberry Pi Imager 安装的 2023-05-03-raspios-bullseye-armhf.img.xz

1.升级到最新版内核保证与下载的内核源码版本一致

$ sudo rpi-update

2.升级完整后重启

$ sudo reboot

3.查看内核版本

$ uname -r

4.把最新版本的内核配置保存到.config中,以备以后编译内核使用

$ sudo modprobe configs

文件被存储到了/proc/config.gz中。

目前最新版本是 6.1.12,当前内核启动默认会切换到 64位内核了,即使安装的是32位系统镜像也是这样。

如果想从32位内核启动,那么需要在 config.txt 中配置 arm_64bit

继续阅读Ubuntu 22.04 (x64)树莓派4B(Raspberry Pi 4B)源代码编译

多线程压缩工具pigz使用

学习Linux系统时都会学习这么几个压缩工具:gzip、bzip2、zip、xz,以及相关的解压工具。关于这几个工具的使用和相互之间的压缩比以及压缩时间对比可以看:Linux中归档压缩工具学习

那么Pigz是什么呢?简单的说,就是支持并行压缩的gzip。Pigz默认用当前逻辑cpu个数来并发压缩,无法检测个数的话,则默认并发8个线程,也可以使用-p指定线程数。需要注意的是其CPU使用比较高。

官网:http://zlib.net/pigz

安装

# centos
$ yum install pigz

# debian / ubuntu
$ sudo apt-ge tinstall pigz

使用方法

$ pigz --help
Usage: pigz [options] [files ...]
  will compress files in place, adding the suffix '.gz'.  If no files are
  specified, stdin will be compressed to stdout.  pigz does what gzip does,
  but spreads the work over multiple processors and cores when compressing.
 
Options:
  -0 to -9, -11        Compression level (11 is much slower, a few % better)
  --fast, --best       Compression levels 1 and 9 respectively
  -b, --blocksize mmm  Set compression block size to mmmK (default 128K)
  -c, --stdout         Write all processed output to stdout (won't delete)
  -d, --decompress     Decompress the compressed input
  -f, --force          Force overwrite, compress .gz, links, and to terminal
  -F  --first          Do iterations first, before block split for -11
  -h, --help           Display a help screen and quit
  -i, --independent    Compress blocks independently for damage recovery
  -I, --iterations n   Number of iterations for -11 optimization
  -k, --keep           Do not delete original file after processing
  -K, --zip            Compress to PKWare zip (.zip) single entry format
  -l, --list           List the contents of the compressed input
  -L, --license        Display the pigz license and quit
  -M, --maxsplits n    Maximum number of split blocks for -11
  -n, --no-name        Do not store or restore file name in/from header
  -N, --name           Store/restore file name and mod time in/from header
  -O  --oneblock       Do not split into smaller blocks for -11
  -p, --processes n    Allow up to n compression threads (default is the
                       number of online processors, or 8 if unknown)
  -q, --quiet          Print no messages, even on error
  -r, --recursive      Process the contents of all subdirectories
  -R, --rsyncable      Input-determined block locations for rsync
  -S, --suffix .sss    Use suffix .sss instead of .gz (for compression)
  -t, --test           Test the integrity of the compressed input
  -T, --no-time        Do not store or restore mod time in/from header
  -v, --verbose        Provide more verbose output
  -V  --version        Show the version of pigz
  -z, --zlib           Compress to zlib (.zz) instead of gzip format
  --                   All arguments after "--" are treated as files

原目录大小:

[20:30 root@hulab /DataBase/Human/hg19]$ du -h
8.1G    ./refgenome
1.4G    ./encode_anno
4.2G    ./hg19_index/hg19
8.1G    ./hg19_index
18G .

接下来我们分别使用gzip以及不同线程数的pigz对h19_index目录进行压缩,比较其运行时间。

### 使用gzip进行压缩(单线程)
[20:30 root@hulab /DataBase/Human/hg19]$ time tar -czvf index.tar.gz hg19_index/
hg19_index/
hg19_index/hg19.tar.gz
hg19_index/hg19/
hg19_index/hg19/genome.8.ht2
hg19_index/hg19/genome.5.ht2
hg19_index/hg19/genome.7.ht2
hg19_index/hg19/genome.6.ht2
hg19_index/hg19/genome.4.ht2
hg19_index/hg19/make_hg19.sh
hg19_index/hg19/genome.3.ht2
hg19_index/hg19/genome.1.ht2
hg19_index/hg19/genome.2.ht2

real    5m28.824s
user    5m3.866s
sys 0m35.314s


### 使用4线程的pigz进行压缩
[20:36 root@hulab /DataBase/Human/hg19]$ ls
encode_anno  hg19_index  index.tar.gz  refgenome
[20:38 root@hulab /DataBase/Human/hg19]$ time tar -cvf - hg19_index/ | pigz -p 4 > index_p4.tar.gz 
hg19_index/
hg19_index/hg19.tar.gz
hg19_index/hg19/
hg19_index/hg19/genome.8.ht2
hg19_index/hg19/genome.5.ht2
hg19_index/hg19/genome.7.ht2
hg19_index/hg19/genome.6.ht2
hg19_index/hg19/genome.4.ht2
hg19_index/hg19/make_hg19.sh
hg19_index/hg19/genome.3.ht2
hg19_index/hg19/genome.1.ht2
hg19_index/hg19/genome.2.ht2

real    1m18.236s
user    5m22.578s
sys 0m35.933s


### 使用8线程的pigz进行压缩
[20:42 root@hulab /DataBase/Human/hg19]$ time tar -cvf - hg19_index/ | pigz -p 8 > index_p8.tar.gz 
hg19_index/
hg19_index/hg19.tar.gz
hg19_index/hg19/
hg19_index/hg19/genome.8.ht2
hg19_index/hg19/genome.5.ht2
hg19_index/hg19/genome.7.ht2
hg19_index/hg19/genome.6.ht2
hg19_index/hg19/genome.4.ht2
hg19_index/hg19/make_hg19.sh
hg19_index/hg19/genome.3.ht2
hg19_index/hg19/genome.1.ht2
hg19_index/hg19/genome.2.ht2

real    0m42.670s
user    5m48.527s
sys 0m28.240s


### 使用16线程的pigz进行压缩
[20:43 root@hulab /DataBase/Human/hg19]$ time tar -cvf - hg19_index/ | pigz -p 16 > index_p16.tar.gz 
hg19_index/
hg19_index/hg19.tar.gz
hg19_index/hg19/
hg19_index/hg19/genome.8.ht2
hg19_index/hg19/genome.5.ht2
hg19_index/hg19/genome.7.ht2
hg19_index/hg19/genome.6.ht2
hg19_index/hg19/genome.4.ht2
hg19_index/hg19/make_hg19.sh
hg19_index/hg19/genome.3.ht2
hg19_index/hg19/genome.1.ht2
hg19_index/hg19/genome.2.ht2

real    0m23.643s
user    6m24.054s
sys 0m24.923s


### 使用32线程的pigz进行压缩
[20:43 root@hulab /DataBase/Human/hg19]$ time tar -cvf - hg19_index/ | pigz -p 32 > index_p32.tar.gz 
hg19_index/
hg19_index/hg19.tar.gz
hg19_index/hg19/
hg19_index/hg19/genome.8.ht2
hg19_index/hg19/genome.5.ht2
hg19_index/hg19/genome.7.ht2
hg19_index/hg19/genome.6.ht2
hg19_index/hg19/genome.4.ht2
hg19_index/hg19/make_hg19.sh
hg19_index/hg19/genome.3.ht2
hg19_index/hg19/genome.1.ht2
hg19_index/hg19/genome.2.ht2

real    0m17.523s
user    7m27.479s
sys 0m29.283s

### 解压文件
[21:00 root@hulab /DataBase/Human/hg19]$ time pigz -p 8 -d index_p8.tar.gz 

real    0m27.717s
user    0m30.070s
sys 0m22.515s

各个压缩时间的比较:

程序 线程数 时间
gzip 1 5m28.824s
pigz 4 1m18.236s
pigz 8 0m42.670s
pigz 16 0m23.643s
pigz 32 0m17.523s

从上面可以看出,使用多线程pigz进行压缩能进行大大的缩短压缩时间,特别是从单线程的gzip到4线程的pigz压缩时间缩短了4倍,继续加多线程数,压缩时间减少逐渐不那么明显。
虽然pigz能大幅度的缩短运行时间,但这是以牺牲cpu为代价的,所以对于cpu使用较高的场景不太宜使用较高的线程数,一般而言使用4线程或8线程较为合适。

参考链接


多线程压缩工具pigz使用

Flutter The Linux toolchain CMake build dependency (CMake 3.14 or higher is required. You are running version 3.10.2)

ubuntu 22.04 通过 snap 安装了 Flutter SDK(当前是Flutter 3.3.4),如果第三方的依赖了 CMake 3.10.2 更高的版本,会在编译的时候报错:

CMake 3.14 or higher is required. You are running version 3.10.2

这个报错的原因是由于 snap 安装的 Flutter SDK 构建了一个沙箱环境,在这个环境中的 CMake3.10.2 版本,不管系统安装的是哪个版本的 CMake ,都是无效的。

要解决这个问题,或者等待 snapFlutter SDK 更新版本,或者参照 Linux install Flutter 的说明,手工安装并配置 Flutter SDK

可以参考如下代码:

$ sudo snap remove flutter

$ sudo apt-get install curl

$ sudo apt-get install clang

$ sudo apt-get install git

$ sudo apt-get install ninja-build

$ sudo apt-get install pkg-config

$ sudo apt install gettext

$ sudo apt-get install libgtk-3-dev

$ sudo apt install libstdc++-12-dev

$ git clone https://github.com/flutter/flutter.git -b stable

$ export PATH="$PATH:`pwd`/flutter/bin"

$ cd `pwd`/flutter/bin 

$ ./flutter doctor

参考链接


Flutter 3.0实现Linux本地化/国际化

参照 Flutter 2.8.1本地化/国际化应用程序名称 可以实现 Android/macOS/iOS/Web 的应用名称相关的国际化。但是在 Linux 应用上如何相同的功能,目前暂时没有一个统一的标准。

研究了许久,终于基本上算是搞定,解决方案如下:

使用 gettext 来实现国际化相关的功能。

首先配置,调整工程的目录如下:

project/
project/linux
project/linux/flutter
project/linux/flutter/CMakeLists.txt
project/linux/locale/en_US/app.po
project/linux/locale/zh_CN/app.mo
project/linux/locale/CMakeLists.txt
project/linux/CMakeLists.txt
project/linux/main.cc
project/linux/my_application.cc
project/linux/my_application.h

对应语言 i18n 相关配置文件的内容如下:

# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10)

set(OUTPUT_NAME "app")
set(LOCALE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(LOCALE_BUILD_DIR "${CMAKE_BINARY_DIR}/locale")
set(LOCALE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/locale")

# Setting up Internationalisation (i18n)
find_package (Intl REQUIRED)
if (Intl_FOUND)
    message(STATUS "Internationalization (i18n) found:")
    message(STATUS " INTL_INCLUDE_DIRS: ${Intl_INCLUDE_DIRS}")
    message(STATUS " INTL_LIBRARIES: ${Intl_LIBRARIES}")
    message(STATUS " Version: ${Intl_VERSION}")
    include_directories(${Intl_INCLUDE_DIRS})
    link_directories(${Intl_LIBRARY_DIRS})
else ()
    message(STATUS "Internationalization (i18n) Not found!")
endif ()

find_package(Gettext REQUIRED)
if (Gettext_FOUND)
    message(STATUS "Gettext found:")
    message(STATUS " Version: ${GETTEXT_VERSION_STRING}")
else ()
    message(STATUS "Gettext Not found!")
endif ()

find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt)

if (GETTEXT_XGETTEXT_EXECUTABLE)

    message(DEBUG " xgettext: ${GETTEXT_XGETTEXT_EXECUTABLE}")
    file(GLOB_RECURSE PO_FILES RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/*.po)
    add_custom_target(
        pot-update
        COMMENT "pot-update: Done."
        DEPENDS ${LOCALE_DIR}/${OUTPUT_NAME}.pot
    )
    add_custom_command(
        TARGET pot-update
        PRE_BUILD
        COMMAND
            ${GETTEXT_XGETTEXT_EXECUTABLE}
            --from-code=utf-8
            --force-po
            --output=${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot
            --keyword=_
            --width=80
            ${PO_FILES}
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        COMMENT "pot-update: Pot file generated: ${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot"
    )
else ()
    message(STATUS "pot-update not created!")
endif (GETTEXT_XGETTEXT_EXECUTABLE)

if (GETTEXT_MSGMERGE_EXECUTABLE)

    message(DEBUG " msgmerge: ${GETTEXT_MSGMERGE_EXECUTABLE}")

    add_custom_target(
        pot-merge
        COMMENT "pot-merge: Done."
        DEPENDS ${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot
    )

    file(GLOB PO_FILES ${LOCALE_DIR}/*/${OUTPUT_NAME}.po)
    message(TRACE " PO_FILES: ${PO_FILES}")

    foreach(PO_FILE IN ITEMS ${PO_FILES})
        message(DEBUG " Adding msgmerge for: ${PO_FILE}")
        add_custom_command(
            TARGET pot-merge
            PRE_BUILD
            COMMAND
                ${GETTEXT_MSGMERGE_EXECUTABLE} ${PO_FILE}
                ${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot
            COMMENT "pot-merge: ${PO_FILE}"
        )
    endforeach()
else ()
    message(STATUS "pot-merge not created!")
endif (GETTEXT_MSGMERGE_EXECUTABLE)

if (GETTEXT_MSGFMT_EXECUTABLE)

    message(DEBUG " msgmerge: ${GETTEXT_MSGFMT_EXECUTABLE}")

    file(GLOB PO_LANGS LIST_DIRECTORIES true ${LOCALE_DIR}/*)
    message(TRACE " PO_LANGS: ${PO_LANGS}")

    add_custom_target(
        po-compile
        COMMENT "po-compile: Done."
    )

    foreach(PO_LANG IN ITEMS ${PO_LANGS})
        if(IS_DIRECTORY ${PO_LANG})
            message(STATUS " Adding msgfmt for: ${PO_LANG}")

            file(RELATIVE_PATH REL_PO_LANG "${LOCALE_DIR}" "${PO_LANG}")
            set(MO_BUILD_DIR "${LOCALE_BUILD_DIR}/${REL_PO_LANG}")
            file(MAKE_DIRECTORY "${MO_BUILD_DIR}")
            set(MO_NAME "${MO_BUILD_DIR}/${OUTPUT_NAME}.mo")

            add_custom_command(
                TARGET po-compile
                PRE_BUILD
                COMMAND
                    ${GETTEXT_MSGFMT_EXECUTABLE}
                    --output-file=${MO_NAME}
                    ${OUTPUT_NAME}.po
                WORKING_DIRECTORY "${PO_LANG}"
                COMMENT "po-compile: ${PO_LANG}"
            )

            install(FILES "${LOCALE_BUILD_DIR}/${REL_PO_LANG}/${OUTPUT_NAME}.mo"
                DESTINATION "${LOCALE_INSTALL_DIR}/${REL_PO_LANG}/LC_MESSAGES"
                COMPONENT Runtime)
        endif()
    endforeach()
else ()
    message(STATUS "pot-compile not created!")
endif (GETTEXT_MSGFMT_EXECUTABLE)

接下来,修改 Linux 工程的配置文件,增加对 本地化(i18n) 文件的引用,在合适的位置增加如下代码:

# locale build and install
set(FLUTTER_LOCALE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/locale")
add_subdirectory(${FLUTTER_LOCALE_DIR})

完整的代码参考如下:

# Project-level configuration.
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)

# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "abc")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "xxx.xxx.xxx")

# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)

# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")

# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
  set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
  set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()

# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  set(CMAKE_BUILD_TYPE "Debug" CACHE
    STRING "Flutter build mode" FORCE)
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
    "Debug" "Profile" "Release")
endif()

# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
  target_compile_features(${TARGET} PUBLIC cxx_std_14)
  target_compile_options(${TARGET} PRIVATE -Wall -Werror)
  target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
  target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()

# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})

# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)

add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")

# Define the application target. To change its name, change BINARY_NAME above,
# not the value here, or `flutter run` will no longer work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
  "main.cc"
  "my_application.cc"
  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)

# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})

# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)

# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)

# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
  PROPERTIES
  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)

# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)

# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} po-compile)

# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()

# locale build and install
set(FLUTTER_LOCALE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/locale")
add_subdirectory(${FLUTTER_LOCALE_DIR})

# Start with a clean build bundle directory every time.
install(CODE "
  file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
  " COMPONENT Runtime)

set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")

install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
  COMPONENT Runtime)

install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
  COMPONENT Runtime)

install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
  COMPONENT Runtime)

foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
  install(FILES "${bundled_library}"
    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
    COMPONENT Runtime)
endforeach(bundled_library)

# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
  " COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)

# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
  install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
    COMPONENT Runtime)
endif()

使用多语言的代码如下:

#include "my_application.h"

#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif

#include <sys/stat.h>
#include <libgen.h>
#include <locale.h>
#include <libintl.h>

#include "flutter/generated_plugin_registrant.h"

#define LOCALE_DIR "/locale/"
#define PACKAGE "app"
#define _(String) gettext(String)

struct _MyApplication
{
  GtkApplication parent_instance;
  char **dart_entrypoint_arguments;
};

G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)

// 118n
static void setup_app_locale()
{
  struct stat sb;
  const char *proc_name = "/proc/self/exe";

  if (lstat(proc_name, &sb) >= 0)
  {

    /* Add one to the link size, so that we can determine whether
    the buffer returned by readlink() was truncated. */
    ssize_t bufsiz = sb.st_size + 1;

    /* Some magic symlinks under (for example) /proc and /sys
    report 'st_size' as zero. In that case, take PATH_MAX as
    a "good enough" estimate. */
    if (0 == sb.st_size)
    {
      bufsiz = PATH_MAX;
    }

    ssize_t loc_dir_len = bufsiz + strlen(LOCALE_DIR) + 1;
    char *buf = (char *)malloc(loc_dir_len);
    if (NULL != buf)
    {
      ssize_t nbytes = readlink(proc_name, buf, bufsiz);
      if (nbytes >= 0)
      {
        /* If the return value was equal to the buffer size, then the
        the link target was larger than expected (perhaps because the
        target was changed between the call to lstat() and the call to
        readlink()). Warn the user that the returned target may have
        been truncated. */

        if (nbytes == bufsiz)
        {
          g_message("(Returned buffer may have been truncated)\n");
        }

        if (nbytes <= bufsiz)
        {
          buf[nbytes] = '\0';
        }

        char *dir = dirname(buf);

        strncat(dir, LOCALE_DIR, strlen(LOCALE_DIR));

        char *loc = setlocale(LC_ALL, NULL);

        g_message("current locale is:%s", loc);
        g_message("locale files dir is:%s", buf);

        setlocale(LC_ALL, "");

        bindtextdomain(PACKAGE, buf);

        textdomain(PACKAGE);
      }
      free(buf);
    }
  }
}

// Implements GApplication::activate.
static void my_application_activate(GApplication *application)
{
  MyApplication *self = MY_APPLICATION(application);
  GtkWindow *window =
      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));

  // Use a header bar when running in GNOME as this is the common style used
  // by applications and is the setup most users will be using (e.g. Ubuntu
  // desktop).
  // If running on X and not using GNOME then just use a traditional title bar
  // in case the window manager does more exotic layout, e.g. tiling.
  // If running on Wayland assume the header bar will work (may need changing
  // if future cases occur).
  gboolean use_header_bar = TRUE;

  setup_app_locale();

#ifdef GDK_WINDOWING_X11
  GdkScreen *screen = gtk_window_get_screen(window);
  if (GDK_IS_X11_SCREEN(screen))
  {
    const gchar *wm_name = gdk_x11_screen_get_window_manager_name(screen);
    if (g_strcmp0(wm_name, "GNOME Shell") != 0)
    {
      use_header_bar = FALSE;
    }
  }
#endif
  if (use_header_bar)
  {
    GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
    gtk_widget_show(GTK_WIDGET(header_bar));
    gtk_header_bar_set_title(header_bar, _("app_name"));
    gtk_header_bar_set_show_close_button(header_bar, TRUE);
    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
  }
  else
  {
    gtk_window_set_title(window, _("app_name"));
  }

  gtk_window_set_default_size(window, 1280, 720);
  gtk_widget_show(GTK_WIDGET(window));

  g_autoptr(FlDartProject) project = fl_dart_project_new();
  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);

  FlView *view = fl_view_new(project);
  gtk_widget_show(GTK_WIDGET(view));
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));

  fl_register_plugins(FL_PLUGIN_REGISTRY(view));

  gtk_widget_grab_focus(GTK_WIDGET(view));
}

// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication *application, gchar ***arguments, int *exit_status)
{
  MyApplication *self = MY_APPLICATION(application);
  // Strip out the first argument as it is the binary name.
  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);

  g_autoptr(GError) error = nullptr;
  if (!g_application_register(application, nullptr, &error))
  {
    g_warning("Failed to register: %s", error->message);
    *exit_status = 1;
    return TRUE;
  }

  g_application_activate(application);
  *exit_status = 0;

  return TRUE;
}

// Implements GObject::dispose.
static void my_application_dispose(GObject *object)
{
  MyApplication *self = MY_APPLICATION(object);
  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}

static void my_application_class_init(MyApplicationClass *klass)
{
  G_APPLICATION_CLASS(klass)->activate = my_application_activate;
  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}

static void my_application_init(MyApplication *self) {}

MyApplication *my_application_new()
{
  return MY_APPLICATION(g_object_new(my_application_get_type(),
                                     "application-id", APPLICATION_ID,
                                     "flags", G_APPLICATION_NON_UNIQUE,
                                     nullptr));
}

参考链接


ubuntu 20.04升级到ubuntu 22.04报错“update-alternatives: 错误: /var/lib/dpkg/alternatives/mpi 损坏:次要链接与主链接 /usr/bin/mpicc 相同”

ubuntu 20.04 升级到 ubuntu 22.04 报错,报错内容如下:

正在设置 openmpi-bin (4.1.2-2ubuntu1) ...
update-alternatives: 错误: /var/lib/dpkg/alternatives/mpi 损坏:次要链接与主链接 /usr/bin/mpicc 相同
dpkg: 处理软件包 openmpi-bin (--configure)时出错:
 已安装 openmpi-bin 软件包 post-installation 脚本 子进程返回错误状态 2
dpkg: 依赖关系问题使得 mpi-default-bin 的配置工作不能继续:
 mpi-default-bin 依赖于 openmpi-bin;然而:
  软件包 openmpi-bin 尚未配置。

dpkg: 处理软件包 mpi-default-bin (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libcoarrays-openmpi-dev:amd64 的配置工作不能继续:
 libcoarrays-openmpi-dev:amd64 依赖于 openmpi-bin;然而:
  软件包 openmpi-bin 尚未配置。

dpkg: 处理软件包 libcoarrays-openmpi-dev:amd64 (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libopenmpi-dev:amd64 的配置工作不能继续:
 libopenmpi-dev:amd64 依赖于 openmpi-bin (>= 3.0.0-1);然而:
  软件包 openmpi-bin 尚未配置。

dpkg: 处理软件包 libopenmpi-dev:amd64 (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libboost-mpi-python1.74.0 的配置工作不能继续:
 libboost-mpi-python1.74.0 依赖因为错误消息指示这是由于上一个问题导致的错误,没有写入 apport 报告。
                  因为错误消息指示这是由于上一个问题导致的错误,没有写入 apport 报告。
      由于已经达到 MaxReports 限制,没有写入 apport 报告。
                                                          由于已经达到 MaxReports 限制,没有写入 apport 报告。
                              由于已经达到 MaxReports 限制,没有写入 apport 报告。
  由于已经达到 MaxReports 限制,没有写入 apport 报告。
                                                      由于已经达到 MaxReports 限制,没有写入 apport 报告。
                          由于已经达到 MaxReports 限制,没有写入 apport 报告。
                                                                              由于已经达到 MaxReports 限制,没有写入 apport 报告。
                                                  由于已经达到 MaxReports 限制,没有写入 apport 报告。
                      由于 mpi-default-bin;然而:
  软件包 mpi-default-bin 尚未配置。

dpkg: 处理软件包 libboost-mpi-python1.74.0 (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libboost-mpi-python1.74-dev 的配置工作不能继续:
 libboost-mpi-python1.74-dev 依赖于 libboost-mpi-python1.74.0 (= 1.74.0-14ubuntu3);然而:
  软件包 libboost-mpi-python1.74.0 尚未配置。

dpkg: 处理软件包 libboost-mpi-python1.74-dev (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libboost-mpi-python-dev 的配置工作不能继续:
 libboost-mpi-python-dev 依赖于 libboost-mpi-python1.74-dev;然而:
  软件包 libboost-mpi-python1.74-dev 尚未配置。

dpkg: 处理软件包 libboost-mpi-python-dev (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libboost-all-dev 的配置工作不能继续:
 libboost-all-dev 依赖于 libboost-mpi-python-dev;然而:
  软件包 libboost-mpi-python-dev 尚未配置。

dpkg: 处理软件包 libboost-all-dev (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 mpi-default-dev 的配置工作不能继续:
 mpi-default-dev 依赖于 libopenmpi-dev;然而:
  软件包 libopenmpi-dev:amd64 尚未配置。

dpkg: 处理软件包 mpi-default-dev (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libboost-mpi1.74-dev 的配置工作不能继续:
 libboost-mpi1.74-dev 依赖于 mpi-default-dev;然而:
  软件包 mpi-default-dev 尚未配置。

dpkg: 处理软件包 libboost-mpi1.74-dev (--configure)时出错:
 依赖关系问题 - 仍未被配置
dpkg: 依赖关系问题使得 libboost-mpi-dev 的配置工作不能继续:
 libboost-mpi-dev 依赖于 libboost-mpi1.74-dev;然而:
  软件包 libboost-mpi1.74-dev 尚未配置。

dpkg: 处理软件包 libboost-mpi-dev (--configure)时出错:
 依赖关系问题 - 仍未被配置
在处理时有错误发生:
 openmpi-bin
 mpi-default-bin
 libcoarrays-openmpi-dev:amd64
 libopenmpi-dev:amd64
 libboost-mpi-python1.74.0
 libboost-mpi-python1.74-dev
 libboost-mpi-python-dev
 libboost-all-dev
 mpi-default-dev
 libboost-mpi1.74-dev
 libboost-mpi-dev
E: Sub-process /usr/bin/dpkg returned an error code (1)

解决方法:

$ sudo mv /var/lib/dpkg/alternatives/mpi /var/lib/dpkg/alternatives/mpi.bak

$ sudo apt-get dist-upgrade

Flutter构建Linux应用

从3.0之后的版本,flutter已经正式支持构建Linux应用

条件

  • ubuntu 22.04
  • Android Studio Chipmunk |  2021.2.1
  • flutter sdk 3.x

方法

1. 打开Linux的平台支持

输入如下指令(如下命令可以使用flutter config查看,2.10以上的版本默认开启

flutter config --enable-linux-desktop

# 其他平台
flutter config --[no-]enable-macos-desktop

flutter config --[no-]enable-windows-desktop

可以使用flutter doctor查看情况。

安装编译依赖

# 安装Android Studio
$ sudo snap install android-studio --classic

# 安装 Flutter SDK
$ sudo snap install flutter

# 更新 Flutter SDK
$ flutter

$ sudo apt-get install cmake

$ sudo apt-get install ninja-build

$ sudo apt-get install clang

$ sudo apt-get install gtk+-3.0

$ sudo apt-get install libssl-dev

$ sudo apt-get install git

$ sudo apt-get install vim
2. 在旧项目中添加Linux平台支持

在项目地址输入如下指令

flutter create --platforms=linux[,macos,windows] .

注意: 项目的名称必须是全小写,如果出现大小写则会报错

"TxxxFxxx" is not a valid Dart package name.

See https://dart.dev/tools/pub/pubspec#name for more information.
3. 构建Linux项目
flutter build linux
4. 报错
Launching lib/main.dart on Linux in debug mode...
Building Linux application...
CMake Error at cmake_install.cmake:66 (file):
  file INSTALL cannot copy file
  "/xxxx/xxxx/build/linux/x64/debug/intermediates_do_not_run/xxx"
  to "/usr/local/xxx": Permission denied.


Exception: Build process failed

出现这个问题

flutter clean //执行这个然后重启 Android Studio

参考链接


SSH默认不支持RSA了

今天升级ubuntu 22.04/Window 11后最基本的ssh登陆突然出问题了, 提示有几种:

Unable to negotiate with UNKNOWN port 65535: no matching host key type found. Their offer: ssh-rsa,ssh-dss
lost connection

sign_and_send_pubkey: no mutual signature supported
Git Pull failed
  Unable to negotiate with xx.xx.xx.xx port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss
   Could not read from remote repository.
   Please make sure you have the correct access rights
   and the repository exists.

一查发现…好嘛, openssh觉得ssh-rsa加密方式不安全, 直接从8.8开始默认不允许这种密钥用于登陆了

解决方法是可以在~/.ssh/config里面加这么一段解决:

Host *
    PubkeyAcceptedKeyTypes +ssh-rsa
    HostKeyAlgorithms +ssh-rsa

第一行说明对所有主机生效, 第二行是将 ssh-rsa 加会允许使用的范围, 第三行是指定所有主机使用的都是 ssh-rsa 算法的key

实测两行都得要写才行, 没有第二行提示没有 ssh-rsa 这么个类型

没有第三行就提示 sign_and_send_pubkey: no mutual signature supported

参考链接


ssh默认不支持rsa了

polkit的pkexec中的本地权限提升漏洞 (CVE-2021-4034)

漏洞简介

漏洞编号: CVE-2021-4034

漏洞产品: PolKit (pkexec)

影响版本: 影响2009年 - 今的版本(当前0.105)

源码获取:

$ apt source policykit-1

​ 或 https://launchpad.net/ubuntu/bionic/+package/policykit-1

继续阅读polkit的pkexec中的本地权限提升漏洞 (CVE-2021-4034)

How to repair a broken/unmountable btrfs filesystem

最近磁盘上的Btrfs分区在调整大小的时候,报错:

$ sudo btrfs check --force --repair /dev/sdb7
enabling repair mode
Opening filesystem to check...
WARNING: filesystem mounted, continuing because of --force
Checking filesystem on /dev/sdb7
UUID: 57e881c6-4aac-4f0c-aed9-74341f525e79
repair mode will force to clear out log tree, are you sure? [y/N]: y
parent transid verify failed on 83801812992 wanted 276510 found 277808
parent transid verify failed on 83801812992 wanted 276510 found 277808
parent transid verify failed on 83801812992 wanted 276510 found 277808
Ignoring transid failure
[1/7] checking root items
parent transid verify failed on 83801812992 wanted 276510 found 277808
Ignoring transid failure
parent transid verify failed on 83800657920 wanted 276512 found 277808
parent transid verify failed on 83800657920 wanted 276512 found 277808
parent transid verify failed on 83800657920 wanted 276512 found 277808
Ignoring transid failure
ERROR: child eb corrupted: parent bytenr=194117632 item=11 parent level=1 child level=1
ERROR: failed to repair root items: Input/output error

How to repair a broken/unmountable btrfs filesystem

The below are the recommended steps for any major btrfs filesystem issue, especially if its unmountable. Reading dmesg or syslog might help you identify which step you could skip to in order to fix a particular problem, but the initial steps are normally useful regardless as btrfs scrub is a very safe repair tool.

  • Boot to a suitable alternative system, such as a rescue shell, different installation of openSUSE, a liveCD, or an openSUSE installation DVD. The installation DVD for the version of openSUSE you are running is usually a good choice as it will certainly use the same kernel/btrfs version. A recent Tumbleweed disk might be better as it will include newer kernel/btrfs
  • Go to a suitable console and make sure you do the below as root
  • Try to mount your partition to /mnt, just to confirm it's really broken
$ mount /dev/sda1 /mnt
  • If it mounts - are you sure it's broken? if Yes - run
$ btrfs scrub start /mnt

to scrub the system, and

$ btrfs scrub status /mnt

to monitor it

  • If it doesn't mount, try to scrub the device just in case it works
$ btrfs scrub start /dev/sda1

and

$ btrfs scrub status /dev/sda1

to monitor. Once complete, try mounting, if yes, you're fixed.

  • If scrubbing is not an option or does not resolve the issue

then instead try mount -o usebackuproot

$ mount -o usebackuproot /dev/sda1 /mnt

Warning: All of the above steps are considered safe and should make no destructive changes to disk. If the above doesn't fix things for you, you can continue with the below steps but the situation is serious enough to justify a bug report, please!

  • Run "btrfs check <device>"
$ btrfs check /dev/sda1

This isn't going to help, but save the log somewhere, it will be useful for the bug report.

  • Seriously consider running "btrfs restore <device> <somewhereto copy data>"
$ btrfs restore /dev/sda1 /mnt/usbdrive

This won't fix anything but it will scan the filesystem and recover everything it can to the mounted device. This especially useful if your btrfs issues are actually caused by failing hardware and not btrfs fault.

  • Run "btrfs rescue super-recover <device>"
$ btrfs rescue super-recover /dev/sda1

Then try to mount the device normally. If it works, stop going.

  • Run "btrfs rescue zero-log <device>"
$ btrfs rescue zero-log /dev/sda1

Then try to mount the device normally. If it works, stop going.

  • Run "btrfs rescue chunk-recover <device>"
$ btrfs rescue chunk-recover /dev/sda1

This will take a LONG while. Then try to mount the device normally. If it works, stop going.

  • If you didn't run it earlier, be sure to now run "btrfs restore <device> <somewhere to copy data>"
$ btrfs restore /dev/sda1 /mnt/usbdrive
  • Failure to use btrfs restore at this point but continuing to attempt repairs means you are at a very high risk of data loss. It is advisable to use btrfs restore to recover as much data as possible before continuing.

Warning: The above tools had a small chance of making unwelcome changes. Below this point there is a higher risk of damage. Do not continue unless you're prepared to accept the consequences of your choice.

  • Now, ONLY NOW, try btrfsck aka "btrfs check --repair <device>"
$ btrfs check --repair /dev/sda1

最后,上面的步骤都不能解决问题,因此最终是把磁盘上的文件全部拷贝出来,然后重新格式化分区,再把文件全部拷贝回去,解决问题。

参考链接