为什么编译要花这么长的时间?

    你的编译器可能有问题。也许它太老了,也许你安装它的时候出了错,也许你用的计算机已经是个古董。在诸如此类的问题上,我无法帮助你。 

    但是,这也是很可能的:你要编译的程序设计得非常糟糕,以至于编译器不得不检查数以百计的头文件和数万行代码。理论上来说,这是可以避免的。如果这是你购 买的库的设计问题,你对它无计可施(除了换一个更好的库),但你可以将你自己的代码组织得更好一些,以求得将修改代码后的重新编译工作降到最少。这样的设 计会更好,更有可维护性,因为它们展示了更好的概念上的分离。 

    看看这个典型的面向对象的程序例子: 

        class Shape {
    
    public:     // 使用Shapes的用户的接口
             virtual void draw() const;
            virtual void rotate(int degrees);
            // ...
        protected:  // common data (for implementers of Shapes)
            Point center;
            Color col;
            // ...
        }; 

        class Circle : public Shape {
        public: 
            void draw() const;
            void rotate(int) { }
            // ...
        protected:
            int radius;
            // ...
        };

        class Triangle : public Shape {
        public: 
            void draw() const;
            void rotate(int);
            // ...
        protected:
            Point a, b, c;
            // ...
        }; 

    设计思想是,用户通过Shapepublic接口来操纵它们,而派生类(例如CircleTriangle)的实现部分则共享由protected成员表现的那部分实现(implementation)。

    然而,这个简单的设计理念里却隐含着三个严重的问题:

    • 这不是一件容易的事情:确定哪些实现部分是对所有的派生类都有用的,并将之共享出来。因此,与 public 接口相比, protected 成员往往要做多得多的改动。举例来说,虽然理论上“中心” (center) 对所有的图形都是一个有效的概念,但当你要维护一个三角形的“中心”的时候,是一件非常麻烦的事情——对于三角形,当且仅当它确实被需要的时候,计算这个中心才是有意义的。  
    • protected 成员很可能要依赖于实现部分的细节,而 Shape 的用户(译注: user 此处译为用户,指使用 Shape 类的代码,下同)却不见得必须依赖它们。举例来说,很多(大多数?)使用 Shape 的代码在逻辑上是与“颜色”无关的,但是由于 Shape 中“颜色”这个定义的存在,却可能需要一堆复杂的头文件,来结合操作系统的颜色概念。  
    • protected 部分发生了改变时,使用 Shape 的代码必须重新编译——即使只有派生类的实现部分才能够访问 protected 成员。

    于是,基类中的“实现相关的信息”(information helpful to implementers)对用户来说变成了象接口一样敏感的东西,它的存在导致了实现部分的不稳定,用户代码的无谓的重编译(当实现部分发生改变时),以及将头文件无节制地包含进用户代码中(因为“实现相关的信息”需要它们)。有时这被称为“脆弱的基类问题”(brittle base class problem) 

    一个很明显的解决方案就是,忽略基类中那些象接口一样被使用的“实现相关的信息”。换句话说,使用接口,纯粹的接口。也就是说,用抽象基类的方式来表示接口: 

        class Shape {
        public:     //使用Shapes的用户的接口
            virtual void draw() const = 0;
            virtual void rotate(int degrees) = 0;
            virtual Point center() const = 0;
            // ...
            // 没有数据
        };

        class Circle : public Shape {
        public: 
            void draw() const;
            void rotate(int) { }
            Point center() const { return center; }
            // ...
        protected:
            Point cent;
            Color col;
            int radius;
            // ...
        }; 

        class Triangle : public Shape {
        public: 
            void draw() const;
            void rotate(int);
            Point center() const;
            // ...
        protected:
            Color col;
            Point a, b, c;
            // ...
        };   

    现在,用户代码与派生类的实现部分的变化之间的关系被隔离了。我曾经见过这种技术使得编译的时间减少了几个数量级。 

    但是,如果确实存在着对所有派生类(或仅仅对某些派生类)都有用的公共信息时怎么办呢?可以简单把这些信息封装成类,然后从它派生出实现部分的类: 

    class Shape {
    public:     //使用Shapes的用户的接口
        virtual void draw() const = 0;
        virtual void rotate(int degrees) = 0;
        virtual Point center() const = 0;
        // ...
        // no data
    }; 

    struct Common {
        Color col;
        // ...
    };       

    class Circle : public Shape, protected Common {
    public: 
        void draw() const;
        void rotate(int) { }
        Point center() const { return center; }
        // ...
    protected:
        Point cent;
        int radius;
    }; 

    class Triangle : public Shape, protected Common {
    public: 
        void draw() const;
        void rotate(int);
        Point center() const;
        // ...
    protected:
        Point a, b, c;
    }; 

原文地址:http://www.research.att.com/~bs/bs_faq2.html#abstract-class

编译时间取决于多个因素,包括: ### ✅ 1. **项目大小** - **OpenWrt**:首次完整编译通常需要 **1~3 小时** - **Linux 内核**:通常需要 **10~30 分钟** - **小型项目**(如单个软件包):几十秒到几分钟 ### ✅ 2. **硬件配置** | 项目 | 影响程度 | 说明 | |------|----------|------| | CPU 核心数 | 高 | 核心越多,`-j$(nproc)` 并行编译越快 | | CPU 性能 | 高 | 高频 CPU 编译更快 | | 内存 | 中 | 内存不足会导致编译失败或卡顿 | | 硬盘类型 | 中 | SSD 比 HDD 快很多,尤其是大量读写时 | ### ✅ 3. **编译环境** - 是否是首次编译(首次需下载源码、编译工具链) - 是否启用大量软件包 - 是否使用缓存(如 `ccache`) --- ### 🕒 常见耗时参考(以 OpenWrt 为例) | 情况 | 编译时间估算 | |------|----------------| | 首次完整编译(普通双核虚拟机) | 2~3 小时 | | 首次完整编译(4 核以上物理机 + SSD) | 30 分钟 ~ 1 小时 | | 增量编译(只编译修改过的部分) | 几分钟 ~ 十几分钟 | | 仅编译内核或单个软件包 | 几分钟以内 | --- ### 🧠 提升编译速度的小技巧 1. 使用 `make -j$(nproc)` 启用并行编译 2. 使用 `make -j$(nproc) V=s` 查看详细日志(不影响速度) 3. 启用 `ccache` 加快重复编译速度: ```bash make menuconfig → Advanced configuration options → Compile the system with ccache ``` 4. 使用 SSD 而不是 HDD 5. 确保有足够的内存(建议至少 4GB,推荐 8GB 或以上) --- ### 📋 总结 | 项目 | 时间估算 | |------|----------| | OpenWrt 首次完整编译 | 1~3 小时 | | Linux 内核编译 | 10~30 分钟 | | 单个软件编译 | 几分钟 | | 增量编译(修改后) | 几分钟 ~ 十几分钟 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值