使用Ubuntu搭建apue环境的绝佳姿势,附带一系列工具操作

4,776 阅读7分钟

一 、前言

最近在研究国外非常受欢的迎知名计算机课程CS631 - APUE,其中配合使用的书籍是《UNIX环境高级编程》一书。目的在于更好的了解类Unix下系统软件(比如一些经常用到的系统命令lsmvcat等等)的实现。以及高级 I/O、文件、信号、 进程关系和进程间通信怎么工作。

在官方课程教学中使用的是NetBSD 9.2系统。对于不想新安装一个虚拟机系统来占用磁盘,或者就想在Ubuntu下进行研究学习的。前期一些必要的工作可以方便后面更好的实践自己的代码。

为了能快速的查看编辑一些源码。也介绍了一下如何通过Windows的Clion编辑虚拟环境代码,以及ssh连接访问虚拟机系统。

本次使用环境

    VMware 16
    Ubuntu 20.04

本次使用软件

    clion
    Tabby Terminal
    sshd
    samba
    cmake
    make
    gcc

二 、apue下载编译及遇到的问题

1. 下载apue

        wget http://www.apuebook.com/src.3e.tar.gz
        tar -zxvf src.3e.tar.gz

2. 安装bsd库

为了使用BSD的实现的C语言标准库,如想要在课程中验证或者使用NetBSD系统源码的一些实现,也可能会用到。

    sudo apt-get install libbsd-dev

安装好后可以在/usr/include/bsd 目录下找到一些如stdio.h头文件

image.png

使用BSD目录的头文件

#include <bsd/stdlib.h>

int main(int argc, char *argv[]) {
      setprogname(argv[0]);
  }

上面面C代码中,使用使用setprogname()函数,在ubuntu默认c标准库上的stdlib.h中是没有这个函数的。

image.png 可以看到我找在/usr/include目录及子目录下到stdlib.h的头文件很多,但是只有/bsd目录下的stdlib头包含有setprogname()函数的声明。

如何链接到使用bsd库的函数

    gcc -c test.c -o test.o -lbsd

3. 编译apue源码

进入到apue解压目录

运行make,出现如下错误

image.png 解决1

打开apue.3e/include目录下的apue.h文件,在其中添加#include <sys/sysmacros.h>

再次make,出现

image.png 解决办法 打开apue.3e/stdio/buf.c,删掉如下代码(文件的89~93行)

        #ifdef _LP64
        #define _flag __pad[4]
        #define _ptr __pad[1]
        #define _base __pad[2]
        #endif

将buf.c文件的95-121行换成下面代码

    int
    is_unbuffered(FILE *fp)
    {
        return(fp->_flags & _IONBF);
    }

    int
    is_linebuffered(FILE *fp)
    {
        return(fp->_flags & _IOLBF);
    }

    int
    buffer_size(FILE *fp)
    {
        #ifdef _LP64
        return(fp->_IO_buf_end - fp->_IO_buf_base);
        #else
        return(BUFSIZ);    /* just a guess */
        #endif
    }

    #else

    #error unknown stdio implementation!

    #endif

也可以直接克隆我修改后的代码 apue.3e-ubuntu20.04 (github.com),再次make,应该就不会有错误了。

最后将apue.h头文件和库文件libapue.a复制到系统目录下。就可以使用了。

 sudo cp /path/to/apue.3e/lib/libapue.a  /usr/lib
 sudo cp /path/to/apue.3e/include/apue.h /usr/include

在编译的时候-lapue链接库

 gcc -c test.c -o test.o -lapue

三 、设置虚拟机网络

主机网络信息

image.png

设置虚拟机网卡模式

image.png 选择桥接模式 -> 配置适配器 -> 找到你使用的网卡(通常和主机一个网卡)。乱选网卡或多选都可能导致虚拟机无法联网。

根据主机IP,给虚拟机设置独立本地IP

根据主机网络信息,网段,选择给虚拟机分配一个固定IP,子网掩码和网关跟主机一样。便于后面主机使用ssh连接虚拟机。 image.png

四 、windows使用Tabby通过ssh连接虚拟机

Ubuntu 上安装 sshd 的详细步骤:

  1. 打开终端,更新软件包列表:
    sudo apt-get update
  1. 安装 openssh-server
    sudo apt-get install openssh-server

3. 启动 sshd 服务:

    sudo systemctl start sshd

如果您使用的是旧版 Ubuntu,则需要将 start 替换为 restart

  1. 验证服务是否成功启动:
    sudo systemctl status sshd

如果服务已成功启动,则状态应显示为 "active (running)"

  1. 启用 sshd 开机自启动:
    sudo systemctl enable sshd

6. 确认 sshd 是否已添加到开机启动项:

    sudo systemctl is-enabled sshd

Tabby连接虚拟机

1. 下载并安装 Tabby

tabby.rs 的官方网站下载 Tabby,根据您的操作系统选择适当的安装包进行下载和安装。

2. 打开终端并启动 Tabby, 创建新会话

配置和连接 -> 新建配置 -> 搜索ssh image.png

3. 配置连接参数

在弹出的 "Connection" 窗口中输入连接参数:

  • "Host": 输入虚拟机的IP地址或主机名。
  • "Port": 输入 SSH 服务监听的端口,默认为22。
  • "Username": 输入虚拟机上的用户名,用于身份验证。
  • "Authentication": 设置身份验证方式。可以选择密码验证、密钥文件验证等。

image.png

4. 连接到虚拟机

完成参数配置后,选择想要连接的虚拟机即可。

image.png

五、 windows 通过samba 访问虚拟机文件系统

1. 安装Samba

sudo apt-get install samba

2. 安装过程中

系统将提示您输入一个管理员密码。请确保使用强密码以保护您的系统。

3. 安装完成后

打开smb.conf文件并进行配置。您可以使用以下命令来打开smb.conf文件:

sudo nano /etc/samba/smb.conf

然后,您可以通过修改文件中的参数来配置Samba服务器,例如共享目录、访问权限等。

最末添加内容如:

[Project]                                                                                               
        comment = project                                                                               
        path = /home/xxx       # 此处为你想要在虚拟机分享的文件路径                                                                         
        browseable = yes                                                                                
        writable = yes                                                                                  
        create mask = 0700                                                                              
        directory mask = 0700                                                                           
        valid users = xxxname        # 一个名字                                                                      
        force user = xxxname                                                                               
        force group = xxxname                                                                              
        public = yes                                                                                    
        available = yes

4. 配置完毕后

运行以下命令重启Samba服务:

sudo service smbd restart

后续操作

sudo smbpasswd -a <用户名>   # 和smb.config中user对应
sudo systemctl restart smbd
sudo systemctl enable smbd
sudo systemctl enable smbd  # 开机自启(可选)

5. 在windows访问Ubuntu samba服务

Win+r 输入网络配置的虚拟机ip,如

image.png 如果win出现你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证来宾访问 提示

解决办法:win+r 输入gpedit.msc

1.找到计算机配置---管理模板---网络---Lanman工作站

2.找到“启用不安全的来宾登录"。

3.选择启用

4.将其固定到快速访问

右键 -> 选择映射网路文件夹,选择一个就行 image.png 现在就可以快速地在虚拟机和主机间快速共享文件了。

六、Clion远程调试

此处打开Clion,你就可以看见前面通过samba共享的文件目录了。

image.png

配置Clion远程调试环境

image.png

  1. 设置ssh连接

settings -> toolchains 添加一个配置环境 -> cedentials 右侧添加ssh配置 -> 按照前面tabby ssh连接差不多设置

  1. 设置远程编译器

在toolchain的剩余选项中,设置好cmake,make,g++,gcc GDB等路径即可。

配置代码Deployment

  1. 选择SFTP,设置好远程环境根目录 image.png
  2. 设置本地映射的文件夹 image.png

七、 编写一段引用apue.h的代码

../01_basic/01_ls.c 文件,模仿ls命令的简单实现

#include "apue.h"
#include <dirent.h>
#include <bsd/stdlib.h>

int main(int argc, char *argv[]) {
  setprogname(argv[0]);
  DIR *dp;
  struct dirent *dirp;
  if (argc != 2)
	err_quit("usage: %s directory_name", getprogname());

  // 打开arg[1]目录,赋值给dp目录指针
  if ((dp = opendir(argv[1])) == NULL)
	err_sys("can't open %s", argv[1]);

  // 读取目录
  while ((dirp = readdir(dp)) != NULL)
	printf("%s\n", dirp->d_name);
  closedir(dp);
  exit(0);
}

1、使用gcc编译

image.png

2、使用Makefile编译

在当前目录下生成目标文件的Makefile

    CC := gcc
    CFLAGS := -Wall
    LDLIBS := -lapue -lbsd

    # 获取所有 .c 文件的名称
    SRCS := $(wildcard *.c)

    # 将 .c 文件的名称替换为对应的 .o 和可执行文件的名称
    OBJS := $(patsubst %.c, %.o, $(SRCS))
    BINS := $(patsubst %.c, %, $(SRCS))

    # 定义默认目标(即 all),使其依赖于所有的可执行文件
    all: $(BINS)

    # 生成可执行文件的规则
    %: %.o
       $(CC) $(CFLAGS) $< $(LDLIBS) -o $@

    # 生成 .o 文件的规则
    %.o: %.c
       $(CC) $(CFLAGS) -c $< -o $@

    # 清理规则
    clean:
       rm -f $(OBJS) $(BINS)

运行Makefile

image.png

统一输出到子目录output文件夹下的Makefile2

    CC := gcc
    CFLAGS := -Wall
    LDLIBS := -lapue -lbsd

    # 获取所有 .c 文件的名称
    SRCS := $(wildcard *.c)

    # 定义输出目录和可执行文件
    OUT_PUT_DIR := output

    # 将 .c 文件的名称替换为对应的 .o 和可执行文件的名称
    OBJS := $(patsubst %.c, output/%.o, $(SRCS))
    BINS := $(patsubst %.c, output/%, $(SRCS))

    # 创建输出目录
    $(OUT_PUT_DIR):
       mkdir -p $(OUT_PUT_DIR)

    # 生成可执行文件的规则
    output/%: output/%.o
       $(CC) $(CFLAGS) $< $(LDLIBS) -o $@

    # 生成 .o 文件的规则
    output/%.o: %.c
       $(CC) $(CFLAGS) -c $< -o $@

    # 定义默认目标(即 all),使其依赖于所有的可执行文件
    all: output $(BINS)

    # 清理规则
    clean:
       rm -f $(OBJS) $(BINS)
       rm -rf $(OUT_PUT_DIR)

运行Makefile2,make -f Makefile2 all image.png.

3、 使用Cmake编译

01_basic同级目录的CMakelists.txt

    cmake_minimum_required(VERSION 3.14)
    project(C_Unix)
    # 使用C99
    set(CMAKE_C_STANDARD 99)

    #
    add_executable(01_basic_01_ls 01_basic/01_ls.c)
    add_executable(01_basic_02_cp 01_basic/02_cp.c)

    # 指定APUE库的头文件和库文件路径
    include_directories(/usr/include)
    link_directories(/usr/lib)

    # 定义变量来保存需要链接的库的名称
    set(LINK_LIBS apue bsd)

    # 链接APUE BSD库
    target_link_libraries(01_basic_01_ls ${LINK_LIBS})
    target_link_libraries(01_basic_02_cp ${LINK_LIBS})

运行Cmake

    mkdir build
    cd build
    cmake ..
    make

八、 总结

  • 经过上面一系列步骤,基本可以实现apue环境编程需求或者有设置类似环境开发的需求。
  • 课程很不错,书籍也很经典,值得学习。