我正在做的项目是一个一步一步的操作系统。
我使用的是 Visual Studio Code 版本 1.85.1 和 Ubuntu 22.04.3 LTS。
当前我正在打开文件夹“Create_Your_Own_OS”,目标是使用 makefile 编译“Lesson9”。
文件夹结构如下:
Create_Your_Own_OS
└───Lesson1
└───Lesson2
└───Lesson3
└───Lesson4
└───Lesson5
└───Lesson6
└───Lesson7
└───Lesson8
└───Lesson9
│ └───include
│ └───common
│ │ types.h
│ └───drivers
│ │ driver.h
│ │ keyboard.h
│ │ mouse.h
│ └───hwComms
│ │ interrupt.h
│ │ port.h
│ └───src
│ └───common
│ │ types.cpp
│ └───drivers
│ │ driver.cpp
│ │ keyboard.cpp
│ │ mouse.cpp
│ └───hwComms
│ │ interrupt.cpp
│ │ port.cpp
│
└───linker.ld
└───makefile
“Lesson9”的代码如下:
端口.h
#ifndef __MYOS__HWCOMMS__PORT_H
#define __MYOS__HWCOMMS__PORT_H
#include <common/types.h>
namespace myos
{
namespace hwComms
{
class Port
{
protected:
Port(myos::common::uint16_t portnumber);
~Port();
myos::common::uint16_t portnumber;
};
class Port8bit: public Port
{
public:
Port8bit(myos::common::uint8_t portnumber);
~Port8bit();
virtual void Write(myos::common::uint8_t portnumber);
virtual myos::common::uint8_t Read();
protected:
static inline myos::common::uint8_t Read8(myos::common::uint16_t _port)
{
myos::common::uint8_t result;
__asm__ volatile("inb %1, %0" : "=a" (result) : "Nd" (_port));
return result;
}
static inline void Write8(myos::common::uint16_t _port, myos::common::uint8_t _data)
{
__asm__ volatile("outb %0, %1" : : "a" (_data), "Nd" (_port));
}
};
class SlowPort8bit : public Port8bit
{
public:
SlowPort8bit(myos::common::uint8_t portnumber);
~SlowPort8bit();
virtual void Write(myos::common::uint8_t portnumber);
protected:
static inline void Write8Slow(myos::common::uint16_t _port, myos::common::uint8_t _data)
{
__asm__ volatile("outb %0, %1\njmp 1f\n1: jmp 1f\n1:" : : "a" (_data), "Nd" (_port));
}
};
class Port16bit : public Port
{
public:
Port16bit(myos::common::uint16_t portnumber);
~Port16bit();
virtual void Write(myos::common::uint16_t portnumber);
virtual myos::common::uint16_t Read();
protected:
static inline myos::common::uint16_t Read16(myos::common::uint16_t _port)
{
myos::common::uint16_t result;
__asm__ volatile("inw %1, %0" : "=a" (result) : "Nd" (_port));
return result;
}
static inline void Write16(myos::common::uint16_t _port, myos::common::uint16_t _data)
{
__asm__ volatile("outw %0, %1" : : "a" (_data), "Nd" (_port));
}
};
class Port32bit : public Port
{
public:
Port32bit(myos::common::uint32_t portnumber);
~Port32bit();
virtual void Write(myos::common::uint32_t portnumber);
virtual myos::common::uint32_t Read();
protected:
static inline myos::common::uint32_t Read32(myos::common::uint16_t _port)
{
myos::common::uint32_t result;
__asm__ volatile("inl %1, %0" : "=a" (result) : "Nd" (_port));
return result;
}
static inline void Write32(myos::common::uint16_t _port, myos::common::uint32_t _data)
{
__asm__ volatile("outl %0, %1" : : "a"(_data), "Nd" (_port));
}
};
}
}
#endif
端口.cpp
#include <include/hwComms/port.h>
using namespace myos::common;
using namespace myos::hwComms;
Port::Port(uint16_t portnumber)
{
this->portnumber = portnumber;
}
Port::~Port()
{
}
Port8bit::Port8bit(uint8_t portnumber)
: Port(portnumber)
{
}
Port8bit::~Port8bit()
{
}
void Port8bit::Write(uint8_t data)
{
Write8(portnumber, data);
}
uint8_t Port8bit::Read()
{
return Read8(portnumber);
}
SlowPort8bit::SlowPort8bit(uint8_t portnumber)
: Port8bit(portnumber)
{
}
SlowPort8bit::~SlowPort8bit()
{
}
void SlowPort8bit::Write(uint8_t data)
{
Write8Slow(portnumber, data);
}
Port16bit::Port16bit(uint16_t portnumber)
: Port(portnumber)
{
}
Port16bit::~Port16bit()
{
}
void Port16bit::Write(uint16_t data)
{
Write16(portnumber, data);
}
uint16_t Port16bit::Read()
{
return Read16(portnumber);
}
Port32bit::Port32bit(uint32_t portnumber)
: Port(portnumber)
{
}
Port32bit::~Port32bit()
{
}
void Port32bit::Write(uint32_t data)
{
Write32(portnumber, data);
}
uint32_t Port32bit::Read()
{
return Read32(portnumber);
}
生成文件
GPPARAMS = -m32 -Iinclude -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -Wno-write-strings
ASPARAMS = --32
LDPARAMS = -melf_i386
objects = obj/loader.o \
obj/gdt.o \
obj/drivers/driver.o \
obj/hwComms/port.o \
obj/hwComms/interruptstubs.o \
obj/hwComms/interrupts.o \
obj/drivers/keyboard.o \
obj/drivers/mouse.o \
obj/kernel.o
obj/%.o: src/%.cpp
mkdir -p $(@D)
gcc $(GPPARAMS) -o $@ -c $\<
obj/%.o: src/%.s
mkdir -p $(@D)
as $(ASPARAMS) -o $@ $\<
mykernel.bin: linkder.ld $(objects)
ld $(LDPARAMS) -T $\< -o $@ $(objects)
install: mykernel.bin
sudo cp $\< /boot/mykernel.bin
mykernel.iso: mykernel.bin
mkdir iso
mkdir iso/boot
mkdir iso/boot/grub
cp $\< iso/boot/mykernel.bin
echo 'set timeout=0' \> iso/boot/grub/grub.cfg
echo 'set default=0' \>\> iso/boot/grub/grub.cfg
echo '' \>\> iso/boot/grub/grub.cfg
echo 'menuentry "My Operating System" {' \>\> iso/boot/grub/grub.cfg
echo ' multiboot /boot/mykernel.bin' \>\> iso/boot/grub/grub.cfg
echo ' boot' \>\> iso/boot/grub/grub.cfg
echo '}' \>\> iso/boot/grub/grub.cfg
grub-mkrescue --output=$@ iso
rm -rf iso
rm ../mykernel.iso
cp $@ ../
run: mykernel.iso
VBoxManage controlvm My_OS poweroff || true
sleep 3 && VBoxManage startvm My_OS
.PHONY: clean
clean:
rm -rf obj mykernel.bin mykernel.iso
要编译“Lesson9”,我进入“Lesson9”的目录并在终端中执行“make”。输出是这样的:
~/Desktop/OS_Development/OS_C/Build_Your_Own_OS/Lesson_9/myos$ make
mkdir -p obj/hwComms
gcc -m32 -Iinclude -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -Wno-write-strings -o obj/hwComms/port.o -c src/hwComms/port.cpp
src/hwComms/port.cpp:2:10: fatal error: include/hwComms/port.h: No such file or directory
2 | #include <include/hwComms/port.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [makefile:18: obj/hwComms/port.o] Error 1
我解决该问题的尝试如下:
将
“包括/hwComms/port.h”
“myos/include/hwComms/port.h”
这些尝试都没有成功。我相信可能需要设置一个环境变量。
理想情况下,我想在 makefile 中设置该变量。
如何找到要包含的文件?您将 #include <...>
中指定的路径
append到
-I
中指定的路径,如果后者是相对的,则将 that 附加到编译器的当前工作目录。如果您有很多-I
,请依次尝试每一个。如果您有#include "..."
,请先尝试源文件本身所在的目录,然后搜索用-I
指定的目录。
现在让我们将其应用到您的示例中。
您将
-Iinclude
传递给 gcc
。您的源文件位于 src/hwComms
。
#include <include/hwComms/port.h>
有用吗?不,因为任何地方都没有include/include/hwComms/port.h
。#include <myos/include/hwComms/port.h>
有用吗?不,因为任何地方都没有include/myos/include/hwComms/port.h
。#include "include/hwComms/port.h"
有用吗?不,因为既没有 src/hwComms/include/hwComms/port.h
也没有
include/include/hwComms/port.h
任何地方。我的建议:
#include <include/....>
毫无意义,目录名称 include
不传达任何信息。更喜欢 #include <hwComms/port.h>
或 #include <myos/hwComms/port.h>
。hwComms/port.h
)的 myos/hwComms/port.h
子目录下有所有头文件(例如 include
或 Lesson9
,具体取决于您选择的样式)。所以你会有例如Lesson9/include/myos/hwComms/port.h
。gcc
(第 9 课)。-Iinclude
传递给它。-I/home/yourname/Desktop/OS_Development/OS_C/Build_Your_Own_OS/Lesson_9/include
)并从您想要的任何目录启动 gcc
。