云计算百科
云计算领域专业知识百科平台

在x86_64 Linux上为RISC-V 64设备交叉编译Navidrome音乐服务器

前言

最近我买了一块RISC-V架构的开发板昉星光2和Orange Pi RV2研究如何作为服务器部署一些服务应用上面玩,尝试在设备上部署Navidrome音乐服务器,但发现github上找不到RISC-V架构的版本。续想根据github的Navidrome项目源码自己编译RISC-V的版本出来。

因为开发板本身的性能有限,直接在其上编译项目太慢。于是,决定在自己的x86_64主机上用linux虚拟机进行交叉编译,然后将编译好的二进制文件部署到开发板上。本文将完整记录整个过程,希望能帮助遇到类似问题的朋友。

一、项目目标

在x86_64架构的Linux主机上,为RISC-V 64架构的目标设备交叉编译并部署Navidrome音乐服务器,规避目标设备资源不足和兼容性问题。

二、主机环境准备 (x64 Debian/Ubuntu虚拟机)

1. 基础编译工具

sudo apt update
sudo apt install -y make gcc g++ zip unzip curl git build-essential cmake python3 python3-dev bison flex texinfo libgmp-dev libmpc-dev libmpfr-dev libisl-dev libexpat1-dev libncurses-dev autoconf automake pkg-config libtag1-dev

2. 安装 Go 语言

# 从官网安装最新版本,我这里选择go1.25.5
wget https://go.dev/dl/go1.25.5.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.25.5.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

3. 安装 Node.js (用于构建前端)

我选择nodejs24,因为网上搜到的文档都是教安装nodejs24+,有兴趣的伙伴可以尝试安装最新nodejs25+ 。

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo bash –
sudo apt-get install -y nodejs

4. 获取 RISC-V 交叉编译工具链

从官方或第三方获取 riscv64-unknown-linux-gnu 工具链,创建目录并解压:

(1)github下载最新riscv64工具链:Releases · riscv-collab/riscv-gnu-toolchain(推荐)

(2)github克隆编译安装:git clone –recursive https://github.com/riscv-collab/riscv-gnu-toolchain.git

# 1.创建工具链安装目录,一般创建在/usr/local下
sudo mkdir /usr/local/riscv64-glibc-toolchain
# 2.解压工具链
sudo tar -xvf riscv64-glibc-ubuntu-24.04-gcc.tar.xz -C /usr/local/riscv64-glibc-toolchain
# 3.将riscv目录整个移到上一层
sudo mv /usr/local/riscv64-glibc-toolchain/riscv/* /usr/local/riscv64-glibc-toolchain
rm -rf /usr/local/riscv64-glibc-toolchain/riscv

# 配置riscv64工具链环境变量~/.bashrc
echo 'export RISCV_TOOLCHAIN_PATH=/usr/local/riscv64-glibc-toolchain' >> ~/.bashrc
echo 'export PATH=$RISCV_TOOLCHAIN_PATH/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

5. 自己编译 Python 3.12(可选,但推荐)

不想编译可以直接在软件仓库APT安装:apt install python

但某些依赖可能需要较新版本的Python:

sudo apt update
sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev libbz2-dev liblzma-dev

# 下载源码包
cd /tmp
wget https://www.python.org/ftp/python/3.12.7/Python-3.12.7.tar.xz
tar -xf Python-3.12.7.tar.xz
cd Python-3.12.7

# 配置编译选项
./configure \\
–enable-optimizations \\
–enable-shared \\
–prefix=/usr/local/python3.12 \\
LDFLAGS="-Wl,-rpath,/usr/local/python3.12/lib"

# 编译并安装(-j8为并发编译线程数,一般cpu多少超线程,除以2为该数值)
make -j8
sudo make install

# 创建符号链接
sudo ln -sf /usr/local/python3.12/bin/python3.12 /usr/local/bin/python3.12
sudo ln -sf /usr/local/python3.12/bin/pip3.12 /usr/local/bin/pip3.12

# 配置库路径
echo '/usr/local/python3.12/lib' | sudo tee /etc/ld.so.conf.d/python3.12.conf
sudo ldconfig

6. 配置工具链别名

编辑 ~/.bashrc 文件,添加以下别名:

# RISC-V 工具链快捷别名
alias rv-gcc='riscv64-unknown-linux-gnu-gcc'
alias rv-g++='riscv64-unknown-linux-gnu-g++'
alias rv-gdb='riscv64-unknown-linux-gnu-gdb'
alias rv-objdump='riscv64-unknown-linux-gnu-objdump'
alias rv-readelf='riscv64-unknown-linux-gnu-readelf'
alias rv-as='riscv64-unknown-linux-gnu-as'
alias rv-ld='riscv64-unknown-linux-gnu-ld'

使配置生效:

source ~/.bashrc

三、获取 Navidrome 源码

cd ~
git clone https://github.com/navidrome/navidrome.git
cd navidrome

如果githu克隆很慢,试试国内源:git clone https://gitcode.com/gh_mirrors/na/navidrome.git

 

四、编译前端 (在 x64 主机完成)

cd ui
npm install
npm run build

验证:ui/build/ 目录下应生成 index.html 和 assets/ 等文件。

 

五、交叉编译关键依赖库

1. 交叉编译 Taglib (核心音频库)

cd ~
wget https://github.com/taglib/taglib/archive/refs/tags/v1.13.tar.gz
tar -xzf v1.13.tar.gz
cd taglib-1.13
mkdir build-riscv64 && cd build-riscv64

cmake .. \\
-DCMAKE_INSTALL_PREFIX=$HOME/riscv64-libs \\
-DCMAKE_SYSTEM_NAME=Linux \\
-DCMAKE_C_COMPILER=/usr/local/riscv64-glibc-toolchain/bin/riscv64-unknown-linux-gnu-gcc \\
-DCMAKE_CXX_COMPILER=/usr/local/riscv64-glibc-toolchain/bin/riscv64-unknown-linux-gnu-g++ \\
-DBUILD_SHARED_LIBS=OFF \\
-DWITH_ASF=ON \\
-DWITH_MP4=ON \\
-DCMAKE_BUILD_TYPE=Release

make -j8
make install

2. 交叉编译 Zlib (解决静态链接问题)

cd ~
wget https://zlib.net/zlib-1.3.1.tar.gz
tar -xzf zlib-1.3.1.tar.gz
cd zlib-1.3.1

export CC=/usr/local/riscv64-glibc-toolchain/bin/riscv64-unknown-linux-gnu-gcc
./configure –static –prefix=$HOME/riscv64-libs
make
make install

六、解决 Taglib 头文件路径问题 (关键步骤)

由于交叉编译环境路径特殊,需要创建包装头文件并修改源码。

1. 创建统一包装头文件

cat > $HOME/riscv64-libs/include/taglib_wrapper_fix.h << 'EOF'
// 首先包含 taglib 主头文件,定义所有基础宏和类型
#include "/home/jack/riscv64-libs/include/taglib/taglib.h"

// 然后包含 taglib_wrapper.cpp 中实际需要的所有头文件
#include "/home/jack/riscv64-libs/include/taglib/apeproperties.h"
#include "/home/jack/riscv64-libs/include/taglib/apetag.h"
#include "/home/jack/riscv64-libs/include/taglib/aifffile.h"
#include "/home/jack/riscv64-libs/include/taglib/asffile.h"
#include "/home/jack/riscv64-libs/include/taglib/dsffile.h"
#include "/home/jack/riscv64-libs/include/taglib/fileref.h"
#include "/home/jack/riscv64-libs/include/taglib/flacfile.h"
#include "/home/jack/riscv64-libs/include/taglib/id3v2tag.h"
#include "/home/jack/riscv64-libs/include/taglib/unsynchronizedlyricsframe.h"
#include "/home/jack/riscv64-libs/include/taglib/synchronizedlyricsframe.h"
#include "/home/jack/riscv64-libs/include/taglib/mp4file.h"
#include "/home/jack/riscv64-libs/include/taglib/mpegfile.h"
#include "/home/jack/riscv64-libs/include/taglib/opusfile.h"
#include "/home/jack/riscv64-libs/include/taglib/tpropertymap.h"
#include "/home/jack/riscv64-libs/include/taglib/vorbisfile.h"
#include "/home/jack/riscv64-libs/include/taglib/wavfile.h"
#include "/home/jack/riscv64-libs/include/taglib/wavpackfile.h"
EOF

2. 修改 Navidrome 源码

cd ~/navidrome
# 使用 sed 命令修改适配器文件,移除对 taglib 的直接引用,改为引用包装头文件
sed -i \\
-e '/^#include <.*\\.h>/ { /<stdlib\\.h>/! { /<string\\.h>/! d; } }' \\
-e '/^#include "taglib_wrapper.h"/i #include "/home/jack/riscv64-libs/include/taglib_wrapper_fix.h"' \\
adapters/taglib/taglib_wrapper.cpp

3. 修改源码处理 DSF 格式支持

编辑 adapters/taglib/taglib_wrapper.cpp 文件:

cd /home/jack/navidrome
view adapters/taglib/taglib_wrapper.cpp

(1)找到第一处 DSF 代码(第52-53行),并在其前后添加条件编译指令。根据 taglib 的常见约定,我们可以使用 TAGLIB_WITH_DSF 宏。修改后该部分应类似:

// 找到第一处 DSF 代码(约第52-53行),添加条件编译
else if (const auto* wavProperties{ dynamic_cast<const TagLib::RIFF::WAV::Properties*>(props) })
bitsPerSample = wavProperties->bitsPerSample();
———————————————————————————–
// 修改为:
else if (const auto* wavProperties{ dynamic_cast<const TagLib::RIFF::WAV::Properties*>(props) })
bitsPerSample = wavProperties->bitsPerSample();

#if TAGLIB_WITH_DSF
else if (const auto* dsfProperties{ dynamic_cast<const TagLib::DSF::Properties*>(props) })
bitsPerSample = dsfProperties->bitsPerSample();
#endif

(2)找到第二处 DSF 代码(第268-271行),同样在其周围添加条件编译指令。你可能需要修改注释行 // —– DSF 附近的结构。修改后应类似:

// 找到第二处 DSF 代码(约第268-271行),同样添加条件编译
// 修改前:
else if (TagLib::DSF::File * dsffile{ dynamic_cast<TagLib::DSF::File *>(f.file())}) {
const TagLib::ID3v2::Tag *tag { dsffile->tag() };
hasCover = tag && !tag->frameListMap()["APIC"].isEmpty();
}

————————————————————————————
// 修改后:
#if TAGLIB_WITH_DSF
// —– DSF
else if (TagLib::DSF::File * dsffile{ dynamic_cast<TagLib::DSF::File *>(f.file())}) {
const TagLib::ID3v2::Tag *tag { dsffile->tag() };
hasCover = tag && !tag->frameListMap()["APIC"].isEmpty();
}
#endif
}

七、交叉编译 Navidrome Go 后端

cd ~/navidrome

# 设置交叉编译环境变量
export GOOS=linux
export GOARCH=riscv64
export CGO_ENABLED=1
export CC=/usr/local/riscv64-glibc-toolchain/bin/riscv64-unknown-linux-gnu-gcc
export CXX=/usr/local/riscv64-glibc-toolchain/bin/riscv64-unknown-linux-gnu-g++

# 设置 CGO 标志,指向本地编译的库
export CGO_CFLAGS="-I$HOME/riscv64-libs/include"
export CGO_LDFLAGS="-L$HOME/riscv64-libs/lib -ltag -ltag_c -lz -static"

# 使用国内 Go 代理加速依赖下载
go env -w GOPROXY=https://goproxy.cn,direct

# 执行交叉编译,使用 netgo 标签
go build -ldflags="-X 'github.com/navidrome/navidrome/consts.gitTag=v0.59-riscv64'" -tags=netgo -o navidrome-riscv64

验证:使用 file navidrome-riscv64 命令检查输出,应包含 "RISC-V" 和 "statically linked" 字样。

八、在 RISC-V 目标设备上部署

1. 传输必要文件

将以下文件从主机传输到目标设备(如 Orange Pi RV2,昉星光2):

  • navidrome-riscv64 二进制文件

2. 设备端配置

# 在目标设备上操作
cd /path/to/navidrome

# 1. 重命名二进制文件(可选)
mv navidrome-riscv64 navidrome
chmod +x navidrome

# 2. 创建配置文件
view navidrome.toml

配置文件navidrome.toml必须修改的配置项:

MusicFolder = "/path/to/your/music" # 音乐库绝对路径
DataFolder = "/path/to/navidrome/data" # 数据目录,确保有写权限

3. 创建管理员用户(必须在启动服务前执行)

./navidrome –configfile navidrome.toml user add –username 用户名 –password 密码

4. 运行与测试

./navidrome –configfile navidrome.toml

访问 http://设备IP:4533 并使用创建的用户登录。

九、配置为系统服务 (长期运行)

在目标设备上创建 systemd 服务文件 /etc/systemd/system/navidrome.service:

[Unit]
Description=Navidrome Music Server
After=network.target

[Service]
User=orangepi
Group=orangepi
Type=simple
ExecStart=/path/to/navidrome –configfile /path/to/navidrome.toml
WorkingDirectory=/path/to/navidrome
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

启用并启动服务:

sudo systemctl daemon-reload
sudo systemctl enable navidrome
sudo systemctl start navidrome
sudo systemctl status navidrome


总结

通过在X64虚拟机上交叉编译riscv64架构的navidrome,我们成功地在资源有限的RISC-V设备上部署了功能完整的Navidrome音乐服务器。这个过程虽然复杂,但掌握了方法后,可以为任何架构的设备编译软件,极大地扩展了嵌入式设备的应用可能性。希望这篇详细的指南能帮助你在自己的项目中也取得成功!

 

赞(0)
未经允许不得转载:网硕互联帮助中心 » 在x86_64 Linux上为RISC-V 64设备交叉编译Navidrome音乐服务器
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!