<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="th">
	<id>https://theory.cpe.ku.ac.th/wiki/index.php?action=history&amp;feed=atom&amp;title=CMake%2FMultiple_Targets</id>
	<title>CMake/Multiple Targets - ประวัติรุ่นแก้ไข</title>
	<link rel="self" type="application/atom+xml" href="https://theory.cpe.ku.ac.th/wiki/index.php?action=history&amp;feed=atom&amp;title=CMake%2FMultiple_Targets"/>
	<link rel="alternate" type="text/html" href="https://theory.cpe.ku.ac.th/wiki/index.php?title=CMake/Multiple_Targets&amp;action=history"/>
	<updated>2026-04-04T03:15:54Z</updated>
	<subtitle>ประวัติรุ่นแก้ไขของหน้านี้ในวิกิ</subtitle>
	<generator>MediaWiki 1.33.1</generator>
	<entry>
		<id>https://theory.cpe.ku.ac.th/wiki/index.php?title=CMake/Multiple_Targets&amp;diff=8799&amp;oldid=prev</id>
		<title>Cardcaptor: หน้าที่ถูกสร้างด้วย &#039;ในโปรเจคซอฟต์แวร์หนึ่งๆ อาจมีการสร้างโปรแกรมที…&#039;</title>
		<link rel="alternate" type="text/html" href="https://theory.cpe.ku.ac.th/wiki/index.php?title=CMake/Multiple_Targets&amp;diff=8799&amp;oldid=prev"/>
		<updated>2010-05-09T22:24:31Z</updated>

		<summary type="html">&lt;p&gt;หน้าที่ถูกสร้างด้วย &amp;#039;ในโปรเจคซอฟต์แวร์หนึ่งๆ อาจมีการสร้างโปรแกรมที…&amp;#039;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;หน้าใหม่&lt;/b&gt;&lt;/p&gt;&lt;div&gt;ในโปรเจคซอฟต์แวร์หนึ่งๆ อาจมีการสร้างโปรแกรมที่สามารถนำไปรันได้โดยตรง (executable)&lt;br /&gt;
หรือไลบรารี (library) มากกว่าหนึ่งอันขึ้นไป (เพื่อให้ง่ายต่อการเขียน &lt;br /&gt;
ผู้เขียนจะเรียกไฟล์ที่คอมไพเลอร์ภาษา C++ สร้างว่า &amp;#039;&amp;#039;target&amp;#039;&amp;#039; ตามที่ Xcode เรียก)&lt;br /&gt;
ซึ่งอาจจะเป็นเพราะ target เหล่านี้เป็นโปรแกรมซึ่งทำงานสนับสนุนซึ่งกันและกัน&lt;br /&gt;
หรือ target บางตัวเป็นไลบรารีซึ่ง target ตัวอื่นเรียกใช้&lt;br /&gt;
ในโพสต์นี้เราจะมาพูดถึงการเขียน CMakeLists.txt เพื่อสร้าง target หลายๆ target&lt;br /&gt;
ในการ build ครั้งเดียว&lt;br /&gt;
&lt;br /&gt;
วิธีการเขียน CMakeLists.txt ให้บรรลุวัตถุประสงค์ข้างบนมีหลายวิธี เราจะนำเสนอวิธีการต่างๆ&lt;br /&gt;
จากง่ายไปยาก โดยวิธีการที่ง่ายๆ นี้หมายความถึงวิธีการที่เขียนไฟล์ง่ายๆ สั้นๆ&lt;br /&gt;
ไม่ต้องเสียแรงมาก แต่ไม่เหมาะสมกับโปรเจคที่มีขนาดไหน &lt;br /&gt;
ส่วนวิธีการที่ยากนั้นเขียนไฟล์ยาวกว่าและอาจจะต้องมีการสร้างไฟล์ CMakeLists.txt เพิ่มเติม&lt;br /&gt;
เพื่อให้จัดการโปรเจคที่ซับซ้อนได้ดียิ่งขึ้น&lt;br /&gt;
&lt;br /&gt;
== Hello World ปะทะ Good Morning ==&lt;br /&gt;
&lt;br /&gt;
สมมติว่าเราจะสร้างโปรเจค sample1 ซึ่งมี target สอง target ดังต่อไปนี้&lt;br /&gt;
&lt;br /&gt;
* helloworld เป็นโปรแกรมพิมพ์ข้อความ &amp;quot;hello, world&amp;quot; ออกทางหน้าจอ&lt;br /&gt;
* goodmorning เป็นโปรแกรมพิมพ์ข้อความ &amp;quot;good morning&amp;quot; ออกทางหน้าจอ&lt;br /&gt;
&lt;br /&gt;
ซึ่งมีซอร์สโค้ดเป็นดังต่อไปนี้&lt;br /&gt;
&lt;br /&gt;
&amp;lt;geshi lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* helloworld.cpp */&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
    printf(&amp;quot;hello, world\n&amp;quot;);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/geshi&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;geshi lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* goodmorning.cpp */&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
    printf(&amp;quot;good morning\n&amp;quot;);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/geshi&amp;gt;&lt;br /&gt;
&lt;br /&gt;
เนื่องจากไฟล์มีอยู่แค่สองไฟล์ เราอาจจะให้ไฟล์ทั้งสองอยู่ในไดเรคทอรีเดียวกันไปเลยดังโครงสร้างไดเรคทอรีข้างล่างนี้&lt;br /&gt;
&lt;br /&gt;
    sample1/&lt;br /&gt;
        src/&lt;br /&gt;
            CMakeLists.txt&lt;br /&gt;
            helloworld.cpp&lt;br /&gt;
            goodmorning.cpp&lt;br /&gt;
&lt;br /&gt;
และในไฟล์ CMakeLists.txt เราสามารถสั่งให้ CMake สร้าง executable สอง executable&lt;br /&gt;
ได้ด้วยการสั่ง ADD_EXECUTABLE สองครั้ง&lt;br /&gt;
&lt;br /&gt;
    PROJECT(sample2)&lt;br /&gt;
    CMAKE_MINIMUM_REQUIRED(VERSION 2.6)&lt;br /&gt;
    &lt;br /&gt;
    ADD_EXECUTABLE(helloworld helloworld.cpp)&lt;br /&gt;
    ADD_EXECUTABLE(goodmorning goodmorning.cpp)&lt;br /&gt;
&lt;br /&gt;
== หนึ่ง target หนึ่งไดเรคทอรี ==&lt;br /&gt;
&lt;br /&gt;
ในการเขียนซอฟต์แวร์ขนาดใหย่ เราอาจพบว่า target สอง target อาจมีการใช้ไฟล์ชื่อเดียวกัน&lt;br /&gt;
ฉะนั้นเราจึงไม่สามารถใส่ไฟล์ของทุก target ไว้ในไดเรคทอรีเดียวกันได้ ฉะนั้นเพื่อให้ไฟล์จัดการง่าย&lt;br /&gt;
เราควรจะแยกไฟล์ของ target แต่ละ target ไว้ในไดเรคทอรีของมันเอง&lt;br /&gt;
&lt;br /&gt;
เราอาจจะจำลองสถานการณ์นั้นโดยแยก helloworld.cpp และ goodmorning.cpp เป็นสองส่วน&lt;br /&gt;
คือ text.h และ main.cpp ดังนี้ (ขออภัยที่การจำลองสถานการ์นี้อาจจะไม่เหมือนจริงไปสักหน่อย)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;geshi lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* text.h ของ helloworld */&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const char *helloworld_text = &amp;quot;hello, world\n&amp;quot;;&lt;br /&gt;
&amp;lt;/geshi&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;geshi lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* main.cpp ของ helloworld */&lt;br /&gt;
#include &amp;quot;text.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
    printf(&amp;quot;%s&amp;quot;, helloworld_text);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/geshi&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;geshi lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* text.h ของ goodmorning */&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
const char *goodmorning_text = &amp;quot;good morning\n&amp;quot;;&lt;br /&gt;
&amp;lt;/geshi&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;geshi lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* main.cpp ของ goodmorning */&lt;br /&gt;
#include &amp;quot;text.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
    printf(&amp;quot;%s&amp;quot;, goodmorning_text);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/geshi&amp;gt;&lt;br /&gt;
&lt;br /&gt;
เราสามารถจัดไฟล์ตามโครงสร้างไดเรคทอรีต่อไปนี้ได้&lt;br /&gt;
&lt;br /&gt;
    sample2/&lt;br /&gt;
        src/&lt;br /&gt;
            CMakeLists.txt&lt;br /&gt;
            helloworld/&lt;br /&gt;
                text.h&lt;br /&gt;
                main.cpp&lt;br /&gt;
            goodmorning/&lt;br /&gt;
                text.h&lt;br /&gt;
                main.cpp&lt;br /&gt;
&lt;br /&gt;
และเขียนไฟล์ CMakeLists.txt ใหม่ว่า&lt;br /&gt;
&lt;br /&gt;
    PROJECT(sample2)&lt;br /&gt;
    CMAKE_MINIMUM_REQUIRED(VERSION 2.6)&lt;br /&gt;
    &lt;br /&gt;
    ADD_EXECUTABLE(helloworld helloworld/text.h helloworld/main.cpp)&lt;br /&gt;
    ADD_EXECUTABLE(goodmorning goodmorning/text.h goodmorning.cpp)&lt;br /&gt;
&lt;br /&gt;
== หนึ่งไดเรคทอรี หนึ่ง CMakeLists.txt ==&lt;br /&gt;
&lt;br /&gt;
สังเกตว่าในตัวอย่างที่แล้ว เวลาเราจะใส่ไฟล์เข้าใน executable หนึ่งๆ&lt;br /&gt;
เราจะต้องใส่ไดเรคทอรีของไฟล์นั้นเข้าไปด้วย เนื่องจากชื่อไฟล์ที่กำหนดใน&lt;br /&gt;
CMakeLists.txt ใดๆ จะเป็นชื่อไฟล์สัมพัทธ์กับไดเรคทอรีที่ CMakeLists.txt&lt;br /&gt;
อยู่เสมอ ซึ่งทำให้เกิดความไม่สะดวกอย่างมาก&lt;br /&gt;
&lt;br /&gt;
นอกจากนี้ หาก target ของเราเป็น target ที่มีไฟล์อยู่หลายไฟล์&lt;br /&gt;
CMakeLists.txt จะต้องมีชื่อไฟล์เหล่านี้ทั้งหมด ทำให้ CMakeLists.txt&lt;br /&gt;
มีขนาดใหญ่มาก ทำให้แก้ไขและจัดการยาก&lt;br /&gt;
&lt;br /&gt;
CMake อนุญาตให้เราเขียน CMakeLists.txt ได้หลายๆ ไฟล์​(แต่ในไดเรคทอรีหนึ่งๆ&lt;br /&gt;
จะมี CMakeLists.txt ได้เพียงไฟล์เดียวเท่านั้น เนื่องจากชื่อไฟล์ซ้ำกันไม่ได้)&lt;br /&gt;
แล้วให้ไฟล์ CMakeLists.txt ของไดเรคทอรีแม่ไปเอาเนื้อหาของ CMakeLists.txt&lt;br /&gt;
ในไดเรคทอรีลูกมาประมวลผลได้ ความสามารถนี้ช่วยให้เราสามารถเขียน CMakeLists.txt&lt;br /&gt;
ของแต่ละ target แยกกันได้หากเราแยกไฟล์ของ target แต่ละตัวอยู่ในไดเรคทอรีของมันแล้ว&lt;br /&gt;
&lt;br /&gt;
เราจะนำตัวอย่างที่แล้วมาดัดแปลงให้ใช้ความสามารถใหม่นี้ อันดับแรกเราจะสร้างไฟล์&lt;br /&gt;
CMakeLists.txt ไว้ในไดเรคทอรี helloworld และ goodmorning อย่างละไฟล์&lt;br /&gt;
ตามโครงสร้างไดเรคทอรีข้างล่าง&lt;br /&gt;
&lt;br /&gt;
    sample3/&lt;br /&gt;
        src/&lt;br /&gt;
            CMakeLists.txt&lt;br /&gt;
            helloworld/&lt;br /&gt;
                CMakeLists.txt&lt;br /&gt;
                text.h&lt;br /&gt;
                main.cpp&lt;br /&gt;
            goodmorning/&lt;br /&gt;
                CMakeLists.txt&lt;br /&gt;
                text.h&lt;br /&gt;
                main.cpp&lt;br /&gt;
&lt;br /&gt;
ในไฟล์ CMakeLists.txt ของไดเรคทอรี src เราเปลี่ยนคำสั่ง ADD_EXECUTABLE&lt;br /&gt;
เป็นคำสั่ง ADD_SUBDIRECTORY เพื่อบอกให้ CMake ไปอ่านและประมวลไฟล์  CMakeLists.txt&lt;br /&gt;
ในไดเรคทอรีย่อยที่กำหนดให้&lt;br /&gt;
&lt;br /&gt;
 ### sample3/src/CMakeLists.txt&lt;br /&gt;
      &lt;br /&gt;
 PROJECT(sample3)&lt;br /&gt;
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)&lt;br /&gt;
 &lt;br /&gt;
 ADD_SUBDIRECTORY(helloworld)&lt;br /&gt;
 ADD_SUBDIRECTORY(goodmorning)&lt;br /&gt;
&lt;br /&gt;
ส่วนในไฟล์ CMakeLists.txt ของ helloworld และ goodmorning&lt;br /&gt;
เราก็ใช้คำสั่ง ADD_EXECUTABLE เหมือนเดิม แต่เราไม่ต้องใส่ชื่อไดเรคทอรีนำหน้าไฟล์ต่างๆ แล้ว&lt;br /&gt;
เนื่องจาก CMakeLists.txt อยู่ในไดเรคทอรีเดียวกับไฟล์พวกนั้นแล้ว&lt;br /&gt;
&lt;br /&gt;
 ### sample3/src/helloworld/CMakeLists.txt&lt;br /&gt;
 &lt;br /&gt;
 ADD_EXECUTABLE(helloworld text.h main.cpp)&lt;br /&gt;
&lt;br /&gt;
 ### sample3/src/goodmorning/CMakeLists.txt&lt;br /&gt;
 &lt;br /&gt;
 ADD_EXECUTABLE(goodmorning text.h main.cpp)&lt;/div&gt;</summary>
		<author><name>Cardcaptor</name></author>
		
	</entry>
</feed>