ส่วนหัวที่คอมไพล์ล่วงหน้าด้วย GCC


91

มีใครประสบความสำเร็จบ้างในการรับส่วนหัวที่คอมไพล์ไว้ล่วงหน้าที่ทำงานกับ GCC บ้าง? ฉันไม่มีโชคในความพยายามของฉันและฉันยังไม่เห็นตัวอย่างที่ดีมากมายสำหรับวิธีการตั้งค่า ฉันได้ลองใช้ cygwin gcc 3.4.4 และใช้ 4.0 บน Ubuntu


ฉันลองแล้วและฉันมีกรณีการใช้งานที่ดีที่สุดสำหรับส่วนหัวที่คอมไพล์ไว้ล่วงหน้าเนื่องจากแหล่ง c ของฉันถูกสร้างขึ้นโดยคอมไพเลอร์และไม่ใช่ผู้ใช้ที่เขียนขึ้น Sun Studio และ Visual Studio โดยเฉพาะปรับปรุงเวลาในการสร้างขึ้นมาก ใน gcc มันแย่ลงเรื่อย ๆ เมื่อไม่มีส่วนหัวที่คอมไพล์ไว้ล่วงหน้า นี่คือ 3.4 ไม่ได้ทดสอบกับ 4.x แต่ความเร็วและ gcc เป็นเอกสิทธิ์เฉพาะบุคคล
Lothar

@Lothar รหัสคืออะไร? ฉันพบว่า g ++ เร็วกว่าคอมไพเลอร์ Visual Studio ล่าสุดประมาณ 10 เท่าในโค้ดที่มีเทมเพลตบางตัว
สุกร

ฉันไม่ได้ใช้เทมเพลตในรหัส C ++ เป็นเพียงการจัดการข้อยกเว้น C + + ส่วนขยาย C ++ ที่ดี แม้ตอนนี้ 6 ปีหลังจากคำถาม VS2010 นี้มีขนาดที่เร็วกว่า แต่ในระหว่างนี้ฉันมี 16 คอร์ดังนั้นฉันจึงสามารถใช้งานได้
Lothar

คำตอบ:


59

ฉันประสบความสำเร็จอย่างแน่นอน ก่อนอื่นฉันใช้รหัสต่อไปนี้:


#include <boost/xpressive/xpressive.hpp>
#include <iostream>

using namespace std;
using namespace boost::xpressive;

//A simple regex test
int main()
{
    std::string hello( "hello world!" );

    sregex rex = sregex::compile( "(\\w+) (\\w+)!" );
    smatch what;

    if( regex_match( hello, what, rex ) )
    {
        std::cout << what[0] << '\n'; // whole match
        std::cout << what[1] << '\n'; // first capture
        std::cout << what[2] << '\n'; // second capture
    }
    return 0;
}

นี่เป็นเพียงสวัสดีชาวโลกจาก Boost Xpressive (ดูลิงค์ด้านล่าง) ก่อนอื่นฉันรวบรวมด้วย-Hตัวเลือกใน gcc มันแสดงรายการส่วนหัวจำนวนมหาศาลที่ใช้ จากนั้นฉันดูแฟล็กคอมไพล์ที่ IDE ของฉัน (รหัส :: บล็อก) กำลังสร้างและเห็นสิ่งนี้:

g++ -Wall -fexceptions -g -c main.cpp -o obj/Debug/main.o

ดังนั้นฉันจึงเขียนคำสั่งเพื่อคอมไพล์ไฟล์ Xpressive.hpp ด้วยแฟล็กเดียวกัน:

sudo g++ -Wall -fexceptions -g /usr/local/include/boost/xpressive/xpressive.hpp

ฉันรวบรวมรหัสเดิมอีกครั้งด้วย-Hและได้รับผลลัพธ์นี้:

g ++ -Wall -fexceptions -H -g -c main.cpp -o obj / Debug / main.o
! /usr/local/include/boost/xpressive/xpressive.hpp.gch
main.cpp
. /usr/include/c++/4.4/iostream
.. /usr/include/c++/4.4/x86_64-linux-gnu/bits/c++config.h
.. /usr/include/c++/4.4/ostream
.. /usr/include/c++/4.4/istream
main.cpp

เดอะ! หมายความว่าคอมไพเลอร์สามารถใช้ส่วนหัวที่คอมไพล์ไว้ล่วงหน้าได้ x หมายความว่าไม่สามารถใช้งานได้ การใช้แฟล็กคอมไพเลอร์ที่เหมาะสมเป็นสิ่งสำคัญ ฉันถอด -H และทำการทดสอบความเร็ว ส่วนหัวที่คอมไพล์ล่วงหน้ามีการปรับปรุงจาก 14 วินาทีเป็น 11 วินาที ไม่เลว แต่ไม่ดี

หมายเหตุ: นี่คือลิงค์ไปยังตัวอย่าง: http://www.boost.org/doc/libs/1_43_0/doc/html/xpressive/user_s_guide.html#boost_xpressive.user_s_guide.examplesฉันไม่สามารถใช้งานได้ใน โพสต์

BTW: ฉันใช้ g ++ ต่อไปนี้

g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3


20
การเพิ่ม -Winvalid-pch จะช่วยให้คุณดีบักถ้าและเหตุใดจึงเกิดข้อผิดพลาดในการใช้งาน PCH
lefticus

ส่วนหัวที่คอมไพล์ไว้ล่วงหน้า "ไม่แย่ แต่ไม่ดี" มีประโยชน์เมื่อคุณมีส่วนหัวจำนวนมากที่เชื่อมโยงกันใหม่ดังนั้นจะช่วยลดเวลาในการคอมไพล์ในโปรเจ็กต์ขนาดใหญ่ที่ใช้ไลบรารีขนาดใหญ่หรือหลาย ๆ ไลบรารี
โจคูน

4
"ไม่แย่ แต่ไม่ดี": ใช้ไฟล์ gcc 4.4.7, 136 .cpp 35.5 Mb ขนาดรวม 148 .h ไฟล์ 5.5 Mb ขนาดไฟล์. gch คือ 48 Mb, Debug build ใช้เวลา 2'20 "(เทียบกับ 2 '14 "non-pch), -O2 build ที่ปรับให้เหมาะสมใช้เวลา 4'30" (เทียบกับ 5'33 "non-pch) ผลที่คาดว่าจะได้รับใกล้เคียงกับการสร้าง debug แต่เป็นเพียงการสร้างที่ได้รับการปรับให้เหมาะสมซึ่งทำกำไรจากการคอมไพล์ล่วงหน้า ไม่แน่ใจว่าทำไม การคอมไพล์ล่วงหน้าเป็นวิธีที่น่าทึ่งกว่าบน Windows!
Andreas Vergison

1
(ต่อ) ไฟล์เอาต์พุต pch / non-pch ที่สอดคล้องกันมีขนาดไบต์ที่เท่ากันนั่นเป็นสิ่งที่ดี การกำหนดเวลาข้างต้นดูเหมือนจะแตกต่างกันไปเมื่อทำการสร้างซ้ำเช่น -O2 non-pch จะแตกต่างกันไประหว่าง 3'45 "ถึง 5'33" ดังนั้นจึงไม่ใช่วิทยาศาสตร์ที่แน่นอนอาจเป็นเพราะทำงานใน VMware อย่างไรก็ตาม gcc pch ดูไม่เป็นประโยชน์เลยในกรณีของฉัน เปรียบเทียบกับฐานรหัสเดียวกันบน Windows VS2012 (x64, คอมไพล์แบบเธรดเดียว): debug 46 "pch, 2'50" non-pch, release 2'13 "pch, 5'02" non-pch และแน่นอนว่าเร็วกว่ามากเมื่อเปิดใช้งานมัลติโปรเซสเซอร์ ...
Andreas Vergison

@AndreasVergison - คุณได้ลองใช้-Winvalid-pchเพื่อให้แน่ใจว่าส่วนหัวที่คอมไพล์ไว้ล่วงหน้าถูกใช้อย่างถูกต้องหรือไม่? เราสังเกตเห็นการปรับปรุงครั้งใหญ่โดยใช้ pch สำหรับรุ่น debug ของเราดังนั้นฉันจึงสงสัยว่ามีปัญหากับการตั้งค่าของคุณหรือไม่
Josh Kelley

52

ประการแรกดูเอกสารประกอบที่นี่

คุณรวบรวมส่วนหัวเช่นเดียวกับไฟล์อื่น ๆ แต่คุณใส่ผลลัพธ์ไว้ในไฟล์ที่มีส่วนต่อท้ายเป็น.gch.

ตัวอย่างเช่นหากคุณคอมไพล์ stdafx.h ล่วงหน้าคุณจะมีส่วนหัวที่คอมไพล์ไว้ล่วงหน้าซึ่งจะถูกค้นหาโดยอัตโนมัติstdafx.h.gchเมื่อใดก็ตามที่คุณรวมstdafx.h

ตัวอย่าง:

stdafx.h:

#include <string>
#include <stdio.h>

ก. cpp:

#include "stdafx.h"
int main(int argc, char**argv)
{
  std::string s = "Hi";
  return 0;
}

จากนั้นรวบรวมเป็น:

> g++ -c stdafx.h -o stdafx.h.gch
> g++ a.cpp
> ./a.out

การคอมไพล์ของคุณจะทำงานได้แม้ว่าคุณจะลบ stdafx.h หลังจากขั้นตอนที่ 1


8

-xระบุสำหรับ C ++ precompiled ส่วนหัวเป็นไม่ได้-x c++-header -x c++ตัวอย่างการใช้งาน PCH มีดังนี้

pch.h:

// Put your common include files here: Boost, STL as well as your project's headers.

main.cpp:

#include "pch.h"
// Use the PCH here.

สร้าง PCH ดังนี้:

$ g++ -x c++-header -o pch.h.gch -c pch.h

pch.h.gchต้องอยู่ในไดเรกทอรีเดียวกันเป็นpch.hเพื่อที่จะนำมาใช้เพื่อให้แน่ใจว่าคุณรันคำสั่งดังกล่าวข้างต้นจากไดเรกทอรีที่pch.hเป็น


3
นี่ควรจะเป็น-c pch.hไม่ใช่-c pch.cppเหรอ?
MM

7

ฉันได้จัดการเพื่อรับส่วนหัวที่คอมไพล์ไว้แล้วซึ่งทำงานภายใต้ gcc ครั้งหนึ่งในอดีตและฉันจำได้ว่ามีปัญหาเช่นกัน สิ่งที่ต้องจำไว้คือ GCC จะไม่สนใจแฟ้ม (header.h.gch หรือคล้ายกัน) ถ้าเงื่อนไขบางอย่างจะไม่พบรายการที่สามารถพบได้ในGCC precompiled หน้าเอกสารของส่วนหัว

โดยทั่วไปจะปลอดภัยที่สุดที่จะให้ระบบบิวด์ของคุณคอมไพล์ไฟล์. gch เป็นขั้นตอนแรกโดยมีตัวเลือกบรรทัดคำสั่งเดียวกันและสามารถเรียกใช้งานได้เหมือนกับแหล่งที่มาของคุณ เพื่อให้แน่ใจว่าไฟล์เป็นข้อมูลล่าสุดและไม่มีความแตกต่างเล็กน้อย

อาจเป็นความคิดที่ดีที่จะทำให้มันใช้งานได้กับตัวอย่างที่สร้างไว้ก่อนเพื่อลบความเป็นไปได้ที่ปัญหาของคุณจะเกิดขึ้นเฉพาะกับซอร์สโค้ดในโครงการของคุณ


7

เรียก gcc แบบเดียวกับที่คุณเรียกสำหรับไฟล์ต้นฉบับ แต่ใช้ไฟล์ส่วนหัว

เช่น

g++ $(CPPFLAGS) test.h

สิ่งนี้จะสร้างไฟล์ชื่อ test.h.gch

ทุกครั้งที่ gcc ค้นหา test ต้องมองหา test.h.gch ก่อนและหากพบว่าจะใช้โดยอัตโนมัติ

ดูข้อมูลเพิ่มเติมได้ในส่วนหัวที่คอมไพล์ของ GCC


ฉันใช้ gcc 3.4 และบรรทัด g ++ stdafx.h จะไม่คอมไพล์คุณได้รับข้อผิดพลาด "g ++: compilation of header file ร้องขอ" แต่จะคอมไพล์ไม่แน่ใจว่าเป็นสิ่งที่ฉันต้องการหรือไม่: "g ++ -c -x c ++ stdafx.h -o stdafx.h.pch "
stefanB

1

ตรวจสอบให้แน่ใจว่า -include your_header.h

นี่คือวิธีที่ฉันbits/stdc++.hรวบรวมและใช้คอลเลคชันล่วงหน้า

รหัส

#include <bits/stdc++.h>

จากนั้นฉันก็หา lib โดยการคอมไพล์ไฟล์ด้วย -H และดูที่เอาต์พุต

g++ sol.cpp -H -O3 -pthread -lm -std=c++14 -o executable

ที่ฉันเห็น

. /usr/include/x86_64-linux-gnu/c++/7/bits/stdc++.h

ดังนั้นฉันจึงสร้างไดเร็กทอรีใหม่bitsภายในไดเร็กทอรีปัจจุบันและคัดลอกstdc++.hจากที่นั่น

จากนั้นฉันก็วิ่ง

g++ bits/stdc++.h -O3 -std=c++14  -pthread

ซึ่งสร้างขึ้น bits/stdc++.gch

โดยปกติฉันรวบรวมรหัสของฉันผ่าน

g++ sol.cpp -O3 -pthread -lm -std=c++14 -o executable

แต่ฉันต้องปรับเปลี่ยนเป็น

g++ sol.cpp -include bits/stdc++.h -O3 -pthread -lm -std=c++14 -o executable

เนื่องจากแก้ไขเฉพาะ.gchไฟล์แทนที่จะเป็น.hด้วย-include bits/stdc++.h นั่นเป็นกุญแจสำคัญสำหรับฉัน สิ่งอื่นที่ควรทราบก็คือคุณต้องรวบรวม*.hไฟล์ส่วนหัวที่มีพารามิเตอร์เกือบเหมือนกับที่คุณรวบรวม*.cppไฟล์. เมื่อฉันไม่รวม-O3หรือ-pthreadไม่สนใจ*.gchส่วนหัวที่คอมไพล์ไว้ล่วงหน้า

หากต้องการตรวจสอบว่าทุกอย่างถูกต้องหรือไม่คุณสามารถวัดความแตกต่างของเวลาโดยการเปรียบเทียบผลของ

time g++ sol.cpp ...

หรือเรียกใช้

g++ sol.cpp -H -O3 -pthread -lm -std=c++14 -o executable

อีกครั้งและมองหาเส้นทางส่วนหัวและถ้าตอนนี้คุณได้รับ!ก่อนเส้นทางไลบรารีเช่น

! ./bits/stdc++.h.gch
....
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.