ไซมอน! ฉันรู้ว่าคุณรู้สึกอย่างไร; ฉันต่อสู้กับส่วนนี้ของการเรียนรู้ Linux ด้วย ขึ้นอยู่กับประสบการณ์ของตัวเองผมเขียนสอนเกี่ยวกับบางส่วนของรายการที่คุณอยู่ (ส่วนใหญ่เป็นข้อมูลอ้างอิงสำหรับตัวเอง!): http://easyaspy.blogspot.com/2008/12/buildinginstalling-application-from.html ฉันคิดว่าคุณจะประทับใจกับบันทึกย่อของฉันเกี่ยวกับความเรียบง่ายของแอปพลิเคชั่น Python ในการสร้าง / ติดตั้ง :)
หวังว่านี่จะช่วยได้! และรวบรวมความสุข
ทิมโจนส์
การสร้าง / ติดตั้งแอปพลิเคชันจากแหล่งข้อมูลใน Ubuntu Linux
ในขณะที่ที่เก็บ Ubuntu นั้นเต็มไปด้วยแอปพลิเคชั่นที่ยอดเยี่ยมในครั้งเดียวหรืออื่นคุณจะต้องพบกับเครื่องมือ "ต้องมี" ที่ไม่ได้อยู่ในที่เก็บ (หรือไม่มีแพ็คเกจ Debian) หรือคุณต้องการ รุ่นใหม่กว่าในที่เก็บ คุณทำอะไร? คุณต้องสร้างแอปพลิเคชันจากแหล่งที่มา! ไม่ต้องกังวลมันไม่ซับซ้อนเท่าที่ฟัง นี่คือเคล็ดลับบางอย่างตามประสบการณ์ของฉันจากการเป็นนักสมัครเล่นอันดับ! (ในขณะที่ฉันใช้ Ubuntu สำหรับตัวอย่างนี้แนวคิดทั่วไปควรใช้กับการแจกจ่าย Unix / Linux ส่วนใหญ่เช่น Fedora และแม้แต่แพลตฟอร์ม Cygwin บน Windows)
กระบวนการพื้นฐานของการสร้าง (รวบรวม) แอปพลิเคชันส่วนใหญ่จากแหล่งที่มาตามลำดับนี้: กำหนดค่า -> รวบรวม -> ติดตั้ง โดยทั่วไป Unix / Linux คำสั่งที่จะทำสิ่งเหล่านี้คือ: config
-> ->make
make install
ในบางกรณีคุณจะพบหน้าเว็บที่แสดงว่าสิ่งเหล่านี้สามารถรวมกันเป็นคำสั่งเดียว:
$ config && make && make install
แน่นอนคำสั่งนี้อนุมานว่าไม่มีปัญหาในขั้นตอนเหล่านี้ นี่คือที่มาของความสนุก!
เริ่มต้นใช้งาน
หากคุณไม่ได้รวบรวมแอปพลิเคชันจากแหล่งที่มาบนระบบของคุณมาก่อนคุณอาจจำเป็นต้องตั้งค่าด้วยเครื่องมือการพัฒนาทั่วไปบางอย่างเช่นgcc
ชุดคอมไพเลอร์ไฟล์ส่วนหัวทั่วไปบางตัว (คิดว่านี่เป็นรหัสที่เขียนแล้ว โดยบุคคลอื่นที่ใช้โดยโปรแกรมที่คุณติดตั้ง) และเครื่องมือสร้าง โชคดีที่ใน Ubuntu มี metapackage ที่เรียกbuild-essential
ว่าจะติดตั้งสิ่งนี้ หากต้องการติดตั้ง (หรือตรวจสอบให้แน่ใจว่าคุณมีอยู่แล้ว!) ให้รันคำสั่งนี้ในเทอร์มินัล:
$ sudo apt-get install build-essential
ตอนนี้คุณมีการตั้งค่าพื้นฐานแล้วให้ดาวน์โหลดไฟล์ต้นฉบับของแอปพลิเคชันและบันทึกลงในไดเรกทอรีที่คุณมีสิทธิ์อ่าน / เขียนเช่นไดเรกทอรี "บ้าน" ของคุณ โดยปกติเหล่านี้จะอยู่ในไฟล์ที่เก็บถาวรที่มีนามสกุลไฟล์อย่างใดอย่างหนึ่งหรือ.tar.gz
ก็หมายความว่ามันเป็น "เทปเก็บ" ซึ่งเป็นกลุ่มของไฟล์ที่เก็บรักษาโครงสร้างไดเรกทอรีญาติของพวกเขา ย่อมาจาก gzip (GNU ไปรษณีย์) ซึ่งเป็นรูปแบบที่นิยม Unix / Linux การบีบอัด ในทำนองเดียวกันย่อมาจาก bzip2 ซึ่งเป็นรูปแบบการบีบอัดที่ใหม่กว่าที่ให้การบีบอัดที่สูงขึ้น (ขนาดไฟล์บีบอัดขนาดเล็ก) กว่า gzip.tar.bz2
.tar
.gz
.bz2
หลังจากที่คุณดาวน์โหลดไฟล์ต้นฉบับให้เปิดหน้าต่างเทอร์มินัล (เทอร์มินัลระบบจากเมนูอูบุนตู) และเปลี่ยนเป็นไดเรกทอรีที่คุณบันทึกไฟล์ (ฉันจะใช้~/download
ในตัวอย่างนี้ที่นี่ '~' เป็นทางลัดไปยังไดเรกทอรี "home" ของคุณ) ใช้คำสั่ง tar เพื่อแยกไฟล์จากไฟล์เก็บถาวรที่ดาวน์โหลดมา:
หากไฟล์ของคุณเป็นไฟล์เก็บถาวร gzip (เช่นลงท้ายด้วย.tar.gz
) ให้ใช้คำสั่ง:
$ tar -zxvf filename.tar.gz
หากไฟล์ของคุณเป็นไฟล์เก็บถาวร bzip2 (เช่นลงท้ายด้วย.tar.bz2
) ให้ใช้คำสั่ง:
$ tar -jxvf filename.tar.gz
เคล็ดลับ: หากคุณไม่ต้องการจำสวิตช์บรรทัดคำสั่งทั้งหมดเพื่อแยกไฟล์เก็บถาวรฉันขอแนะนำให้รับยูทิลิตี้เหล่านี้หนึ่ง (หรือทั้งสองอย่าง): dtrx (รายการโปรด!) หรือ deco (เป็นที่นิยมมากกว่า) ด้วยยูทิลิตี้เหล่านี้อย่างใดอย่างหนึ่งคุณเพียงแค่ใส่ชื่อของยูทิลิตี้ (dtrx หรือ deco) และชื่อไฟล์มันจะทำทั้งหมดที่เหลือ ทั้งสองวิธีนี้ "รู้" ว่าจะจัดการกับรูปแบบการเก็บถาวรส่วนใหญ่ที่คุณน่าจะเจอได้อย่างไรและพวกเขาก็มีข้อผิดพลาดที่ยอดเยี่ยม
เมื่อสร้างจากแหล่งที่มามีข้อผิดพลาดทั่วไปสองประเภทที่คุณน่าจะพบ:
- ข้อผิดพลาดของการกำหนดค่าเกิดขึ้นเมื่อคุณเรียกใช้สคริปต์การกำหนดค่า (โดยปกติจะเป็นชื่อการกำหนดค่าหรือกำหนดค่า) เพื่อสร้าง makefile ที่เฉพาะเจาะจงสำหรับการตั้งค่าของคุณ
- ข้อผิดพลาดของคอมไพเลอร์เกิดขึ้นเมื่อคุณรันคำสั่ง make (หลังจากสร้าง makefile แล้ว) และคอมไพเลอร์ไม่สามารถหารหัสบางอย่างที่ต้องการ
เราจะดูสิ่งเหล่านี้และหารือเกี่ยวกับวิธีการแก้ไข
ข้อผิดพลาดในการกำหนดค่าและการกำหนดค่า
หลังจากที่คุณแตกไฟล์เก็บถาวรซอร์สโค้ดในเทอร์มินัลคุณควรเปลี่ยนเป็นไดเร็กทอรีที่มีไฟล์ที่แตกแล้ว โดยทั่วไปชื่อไดเรกทอรีนี้จะเหมือนกับชื่อของไฟล์ (ไม่มี.tar.gz
หรือ.tar.bz2
นามสกุล) อย่างไรก็ตามบางครั้งชื่อไดเรกทอรีเป็นเพียงชื่อของแอปพลิเคชันโดยไม่มีข้อมูลรุ่นใด ๆ
ในไดเรกทอรีต้นทางให้ค้นหาREADME
ไฟล์และ / หรือINSTALL
ไฟล์ (หรือบางอย่างที่มีชื่อคล้ายกัน) ไฟล์เหล่านี้มักจะมีข้อมูลที่เป็นประโยชน์เกี่ยวกับวิธีการสร้าง / คอมไพล์แอปพลิเคชันและติดตั้งรวมถึงข้อมูลเกี่ยวกับการพึ่งพา "การพึ่งพา" เป็นเพียงชื่อแฟนซีสำหรับส่วนประกอบหรือไลบรารีอื่น ๆ ที่จำเป็นต้องมีการรวบรวมสำเร็จ
หลังจากที่คุณได้อ่านREADME
และ / หรือINSTALL
ไฟล์ (และหวังว่ามองเอกสารออนไลน์ใด ๆ ที่เกี่ยวข้องกับการใช้งาน) ดูการปฏิบัติการ (มี "x" การตั้งค่าสิทธิ์ที่ไฟล์) ไฟล์ชื่อหรือconfig
configure
บางครั้งไฟล์อาจมีนามสกุลเช่น.sh
(เช่นconfig.sh
) นี่เป็นเชลล์สคริปต์ที่รันยูทิลิตีอื่น ๆ เพื่อยืนยันว่าคุณมีสภาพแวดล้อม "สติ" สำหรับการรวบรวม มันจะตรวจสอบเพื่อให้แน่ใจว่าคุณได้ติดตั้งทุกอย่างที่คุณต้องการ
เคล็ดลับ: ถ้านี้เป็นโปรแกรม Python-based แทนไฟล์ config setup.py
คุณควรจะหาไฟล์ชื่อ แอพพลิเคชั่นของ Python นั้นง่ายมากในการติดตั้ง ในการติดตั้งแอปพลิเคชันนี้ในฐานะที่เป็นรูท (เช่นวาง sudo ไว้ด้านหน้าคำสั่งต่อไปนี้ภายใต้ Ubuntu) ให้เรียกใช้คำสั่งนี้:
$ python setup.py install
นั่นควรเป็นสิ่งที่คุณต้องทำ คุณสามารถข้ามส่วนที่เหลือของบทช่วยสอนนี้และดำเนินการต่อเพื่อใช้และเพลิดเพลินกับแอปพลิเคชันของคุณโดยตรง
รันสคริปต์การกำหนดค่าในเทอร์มินัล โดยทั่วไปแล้วคุณสามารถ (และควร!) เรียกใช้สคริปต์การกำหนดค่าด้วยบัญชีผู้ใช้ปกติของคุณ
$ ./config
สคริปต์จะแสดงข้อความเพื่อให้คุณทราบว่ามันทำอะไรอยู่ บ่อยครั้งที่สคริปต์จะให้การบ่งชี้ว่ามันสำเร็จหรือล้มเหลวและหากล้มเหลวจะมีข้อมูลบางอย่างเกี่ยวกับสาเหตุของความล้มเหลว หากคุณไม่ได้รับข้อความแสดงข้อผิดพลาดใด ๆ โดยทั่วไปคุณสามารถสันนิษฐานได้ว่าทุกอย่างเรียบร้อยดี
หากคุณไม่พบสคริปต์ใด ๆ ที่ดูเหมือนสคริปต์กำหนดค่าแสดงว่าโดยทั่วไปแล้วหมายความว่าแอปพลิเคชันนั้นง่ายมากและเป็นแพลตฟอร์มที่เป็นอิสระ ซึ่งหมายความว่าคุณสามารถข้ามไปยังขั้นตอนการสร้าง / คอมไพล์ด้านล่างเนื่องจากข้อมูลที่เตรียมไว้Makefile
ควรใช้กับระบบใดก็ได้
ตัวอย่าง
ในบทช่วยสอนนี้ฉันจะใช้เครื่องอ่าน RSS แบบข้อความที่ชื่อว่า Newsbeuter เป็นตัวอย่างสำหรับประเภทของข้อผิดพลาดที่คุณอาจพบเมื่อสร้างแอปพลิเคชันของคุณ สำหรับ Newsbeuter config.sh
ชื่อของสคริปต์การกำหนดค่าที่เป็น ในระบบของฉันเมื่อฉันทำงานconfig.sh
ข้อผิดพลาดต่อไปนี้เกิดขึ้น:
tester@sitlabcpu22:~/download/newsbeuter-1.3$ ./config.sh
Checking for package sqlite3... not found
You need package sqlite3 in order to compile this program.
Please make sure it is installed.
เมื่อทำการวิจัยบางอย่างฉันพบว่าอันที่จริงแล้วsqlite3
แอปพลิเคชันได้รับการติดตั้ง อย่างไรก็ตามตั้งแต่ฉันพยายามที่จะสร้างจากแหล่งนี้เป็นเคล็ดลับที่ว่าสิ่งที่config.sh
เป็นจริงมองหาห้องสมุดการพัฒนา (ส่วนหัว) sqlite3
สำหรับ ใน Ubuntu แพคเกจส่วนใหญ่มีแพ็คเกจการพัฒนาที่เกี่ยวข้องซึ่งลงท้าย-dev
ด้วย (แพลตฟอร์มอื่น ๆ เช่น Fedora มักใช้ส่วนต่อท้ายของแพ็คเกจ-devel
สำหรับแพ็คเกจการพัฒนา)
เพื่อค้นหาแพ็คเกจที่เหมาะสมสำหรับแพ็คเกจการsqlite3
พัฒนาเราสามารถใช้apt-cache
ยูทิลิตีใน Ubuntu (และในทำนองเดียวกันyum
ยูทิลิตี้ใน Fedora):
tester@sitlabcpu22:~/download/newsbeuter-1.3$ sudo apt-cache search sqlite
คำสั่งนี้ส่งกลับรายการผลลัพธ์ที่ค่อนข้างใหญ่ดังนั้นเราต้องทำงานนักสืบเล็กน้อยเพื่อตรวจสอบว่าแพคเกจใดเหมาะสม libsqlite3-dev
ในกรณีนี้แพคเกจที่เหมาะสมจะออกมาเป็น ขอให้สังเกตว่าบางครั้งแพคเกจที่เรากำลังมองหาจะมีคำนำหน้าแทนเพียงแค่ชื่อแพคเกจเดียวกันบวกlib
-dev
นี่เป็นเพราะบางครั้งเราแค่มองหาไลบรารี่ที่แชร์ซึ่งอาจถูกใช้งานโดยแอพพลิเคชั่นต่าง ๆ มากมาย หากต้องการติดตั้งlibsqlite3-dev
ให้รันคำสั่ง apt-get install ในเทอร์มินัล:
tester@sitlabcpu22:~/download/newsbeuter-1.3$ sudo apt-get install libsqlite3-dev
ตอนนี้เราต้องทำงานconfig.sh
อีกครั้งเพื่อให้แน่ใจว่าเราได้แก้ไขปัญหาการพึ่งพานี้แล้วและเราไม่มีปัญหาการพึ่งพาอีกต่อไป (แม้ว่าฉันจะไม่แสดงที่นี่ในกรณีของ Newsbeuter ฉันก็ต้องติดตั้งlibcurl4-openssl-dev
แพคเกจด้วย) นอกจากนี้หากคุณติดตั้งแพคเกจการพัฒนา (เช่นlibsqlite3-dev
) และแอปพลิเคชันแพคเกจที่เกี่ยวข้อง (เช่นsqlite3
) ติดตั้งแล้วระบบส่วนใหญ่จะติดตั้งแพคเกจแอปพลิเคชันที่เกี่ยวข้องโดยอัตโนมัติในเวลาเดียวกัน
เมื่อการกำหนดค่ารันสำเร็จผลลัพธ์จะเป็นว่ามันจะสร้างไฟล์อย่างน้อยหนึ่งไฟล์ โดยทั่วไปไฟล์เหล่านี้จะตั้งชื่อMakefile
(จำไว้ว่าชื่อไฟล์มีความสำคัญใน Unix / Linux!) หากแพ็คเกจการสร้างมีไดเรกทอรีย่อยเช่นsrc
ฯลฯ แต่ละไดเรกทอรีย่อยเหล่านี้จะมีMakefile
เช่นกัน
ข้อผิดพลาดในการสร้างและการรวบรวม
ตอนนี้เราพร้อมที่จะรวบรวมแอปพลิเคชันจริงแล้ว สิ่งนี้มักเรียกว่าการสร้างและชื่อนั้นยืมมาจากกระบวนการโลกแห่งการสร้างบางสิ่งบางอย่าง "ชิ้นส่วน" ของแอปพลิเคชั่นซึ่งโดยทั่วไปจะเป็นไฟล์ซอร์สโค้ดหลายไฟล์ถูกรวมเข้าด้วยกันเพื่อสร้างแอปพลิเคชันโดยรวม ยูทิลิตี make จะจัดการกระบวนการสร้างและเรียกใช้แอปพลิเคชันอื่นเช่นคอมไพเลอร์และลิงเกอร์เพื่อทำงานจริง ในกรณีส่วนใหญ่คุณเพียงแค่เรียกใช้ make (ด้วยบัญชีผู้ใช้ปกติของคุณ) จากไดเรกทอรีที่คุณรันการกำหนดค่า (ในบางกรณีเช่นการรวบรวมแอปพลิเคชันที่เขียนด้วยไลบรารี Qt คุณจะต้องเรียกใช้แอปพลิเคชั่น "wrapper" อื่น ๆ เช่น qmake แทนตรวจสอบรายละเอียดREADME
และ / หรือINSTALL
เอกสารทุกครั้ง)
เช่นเดียวกับสคริปต์การกำหนดค่าด้านบนเมื่อคุณเรียกใช้ make (หรือยูทิลิตี้ที่คล้ายกัน) ในเทอร์มินัลมันจะแสดงข้อความบางอย่างเกี่ยวกับสิ่งที่กำลังดำเนินการและคำเตือนและข้อผิดพลาดใด ๆ โดยทั่วไปคุณสามารถเพิกเฉยต่อคำเตือนเนื่องจากเป็นส่วนใหญ่สำหรับนักพัฒนาแอปพลิเคชันและกำลังบอกพวกเขาว่ามีวิธีปฏิบัติมาตรฐานบางอย่างที่ถูกละเมิด โดยปกติแล้วคำเตือนเหล่านี้จะไม่ส่งผลกระทบต่อฟังก์ชันแอปพลิเคชัน ในทางตรงกันข้ามข้อผิดพลาดของคอมไพเลอร์จะต้องได้รับการจัดการ เมื่อใช้ Newsbeuter เมื่อฉันทำสิ่งต่างๆมาเป็นระยะเวลาหนึ่งแล้วฉันก็พบข้อผิดพลาด:
tester@sitlabcpu22:~/download/newsbeuter-1.3$ make
...
c++ -ggdb -I/sw/include -I./include -I./stfl -I./filter -I. -I./xmlrss -Wall -Wextra -DLOCALEDIR=\"/usr/local/share/locale\" -o src/configparser.o -c src/configparser.cpp
c++ -ggdb -I/sw/include -I./include -I./stfl -I./filter -I. -I./xmlrss -Wall -Wextra -DLOCALEDIR=\"/usr/local/share/locale\" -o src/colormanager.o -c src/colormanager.cpp
In file included from ./include/pb_view.h:5,
from src/colormanager.cpp:4:
./include/stflpp.h:5:18: error: stfl.h: No such file or directory
In file included from ./include/pb_view.h:5,
from src/colormanager.cpp:4:
./include/stflpp.h:33: error: ISO C++ forbids declaration of \u2018stfl_form\u2019 with no type
./include/stflpp.h:33: error: expected \u2018;\u2019 before \u2018*\u2019 token
./include/stflpp.h:34: error: ISO C++ forbids declaration of \u2018stfl_ipool\u2019 with no type
./include/stflpp.h:34: error: expected \u2018;\u2019 before \u2018*\u2019 token
make: *** [src/colormanager.o] Error 1
กระบวนการทำให้จะหยุดทันทีที่พบข้อผิดพลาดแรก การจัดการข้อผิดพลาดของคอมไพเลอร์บางครั้งอาจเป็นเรื่องยุ่งยาก คุณต้องดูข้อผิดพลาดสำหรับเบาะแสบางอย่างเกี่ยวกับปัญหา โดยทั่วไปปัญหาคือไฟล์ส่วนหัวบางไฟล์ซึ่งมักจะมีนามสกุล.h
หรือ.hpp
หายไป ในกรณีที่มีข้อผิดพลาดข้างต้นเป็น (หรือควรเป็น!) ชัดเจนว่าปัญหาคือstfl.h
ไม่พบไฟล์ส่วนหัว ดังที่ตัวอย่างนี้แสดงขึ้นมาคุณต้องการดูบรรทัดแรกของข้อความแสดงข้อผิดพลาดและหาทางแก้ไขเพื่อหาสาเหตุของปัญหา
หลังจากดูเอกสารของ Newsbeuter (ซึ่งฉันควรทำก่อนที่ฉันจะเริ่ม แต่ส่วนหนึ่งของบทช่วยสอนนี้ไม่มีความหมายมาก!) ฉันพบว่ามันต้องมีห้องสมุดบุคคลที่สามที่เรียกว่า STFL แล้วเราจะทำอย่างไรในกรณีนี้? ทีนี้เราก็ทำซ้ำกระบวนการเดียวกันนี้สำหรับไลบรารีที่ต้องการนั้น: ขอรับไลบรารีและดำเนินการกระบวนการกำหนดค่า - บิลด์ - ติดตั้งสำหรับมันและจากนั้นสร้างแอปพลิเคชันที่ต้องการต่อ ตัวอย่างเช่นในกรณีของ STFL ฉันต้องติดตั้งlibncursesw5-dev
แพ็กเกจเพื่อสร้างอย่างถูกต้อง (โดยปกติไม่จำเป็นต้องทำซ้ำขั้นตอนการกำหนดค่าในแอปพลิเคชันเดิมของเราหลังจากติดตั้งแอปพลิเคชันอื่นที่จำเป็น แต่ไม่เคยเจ็บอย่างใดอย่างหนึ่ง)
หลังจากติดตั้งชุดเครื่องมือ STFL สำเร็จกระบวนการสร้างสำหรับ Newsbeuter จะทำงานได้สำเร็จ โดยทั่วไปกระบวนการสร้างจะเลือกตำแหน่งที่จะปิด (ที่จุดของข้อผิดพลาด) ดังนั้นไฟล์ใด ๆ ที่คอมไพล์แล้วสำเร็จจะไม่ถูกคอมไพล์ใหม่ หากคุณต้องการคอมไพล์ทุกสิ่งใหม่คุณสามารถเรียกใช้ make clean all เพื่อลบออบเจ็กต์ที่รวบรวมแล้วเรียกใช้ make อีกครั้ง
การติดตั้ง
หลังจากกระบวนการสร้างเสร็จสมบูรณ์คุณก็พร้อมที่จะติดตั้งแอปพลิเคชัน ในกรณีส่วนใหญ่หากต้องการติดตั้งแอปพลิเคชันไปยังพื้นที่ทั่วไปของระบบไฟล์ (เช่น/usr/bin
หรือ/usr/share/bin
อื่น ๆ ) คุณจะต้องเรียกใช้การติดตั้งในฐานะรูท การติดตั้งเป็นขั้นตอนที่ง่ายที่สุดในกระบวนการทั้งหมด ในการติดตั้งในการรันเทอร์มินัล:
$ make install
ตรวจสอบผลลัพธ์ของกระบวนการนี้เพื่อหาข้อผิดพลาด หากทุกอย่างประสบความสำเร็จคุณควรจะสามารถเรียกใช้ชื่อคำสั่งในเทอร์มินัลและมันจะเปิดตัว (ผนวก & ต่อท้ายบรรทัดคำสั่งหากเป็นแอปพลิเคชั่น GUI มิฉะนั้นคุณจะไม่สามารถใช้เซสชันเทอร์มินัลจนกว่าแอปพลิเคชันจะทำงานเสร็จสิ้น)
เมื่อคุณสร้างแอปพลิเคชันจากแหล่งที่มาโดยทั่วไปจะไม่เพิ่มไอคอนหรือทางลัดไปยังเมนู GUI ใน Ubuntu คุณจะต้องเพิ่มสิ่งนี้ด้วยตนเอง
และนั่นเป็นกระบวนการแม้ว่าจะซ้ำไปซ้ำมาเพื่อสร้างและติดตั้งแอปพลิเคชันจากแหล่งใน Ubuntu หลังจากที่คุณทำสิ่งนี้เพียงไม่กี่ครั้งมันจะกลายเป็นเรื่องปกติสำหรับคุณ!