์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ C++ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๊ณผ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ ๋Œ€์ƒ ๋นŒ๋“œ ํ™˜๊ฒฝ ๊ตฌ์„ฑ

๐Ÿš€ C++ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๊ณผ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ ๋Œ€์ƒ ๋นŒ๋“œ ํ™˜๊ฒฝ ๊ตฌ์„ฑ

ํ•œ ๋ฒˆ์˜ ์ฝ”๋“œ๋กœ ๋ชจ๋“  ํ”Œ๋žซํผ์„ ์ •๋ณตํ•˜๋Š” ๋งˆ๋ฒ• ๊ฐ™์€ ์—ฌ์ •

์•ˆ๋…•! ์˜ค๋Š˜์€ C++ ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ํ•œ ๋ฒˆ์ฏค์€ ๊ณ ๋ฏผํ•ด๋ดค์„ ์ฃผ์ œ, ๋ฐ”๋กœ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๊ณผ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๋นŒ๋“œ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด๋ณด๋ ค๊ณ  ํ•ด. ๐ŸŽฏ

์ƒ์ƒํ•ด๋ด. ๋„ˆ๊ฐ€ ๋งŒ๋“  ๋ฉ‹์ง„ C++ ํ”„๋กœ๊ทธ๋žจ์ด Windows์—์„œ๋งŒ ๋Œ์•„๊ฐ„๋‹ค๋ฉด? ๋งฅ ์‚ฌ์šฉ์ž๋“ค์€ "๋‚˜๋„ ์“ฐ๊ณ  ์‹ถ์€๋ฐ..."๋ผ๋ฉฐ ์•„์‰ฌ์›Œํ•  ๊ฑฐ์•ผ. ๋ฆฌ๋ˆ…์Šค ์„œ๋ฒ„์— ๋ฐฐํฌํ•˜๋ ค๋ฉด ๋˜ ๋‹ค์‹œ ์ฒ˜์Œ๋ถ€ํ„ฐ? ์•„๋‹ˆ์•ผ, ๊ทธ๋Ÿด ํ•„์š” ์—†์–ด! ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ๋งˆ์Šคํ„ฐํ•˜๋ฉด ํ•œ ๋ฒˆ์˜ ์ฝ”๋“œ ์ž‘์„ฑ์œผ๋กœ ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์„ ๋™์‹œ์— ๊ณต๋žตํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๋“ฏ์ด, ๋„ˆ์˜ ์ฝ”๋“œ๋„ ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์—์„œ ์ž์œ ๋กญ๊ฒŒ ๊ณต์œ ๋  ์ˆ˜ ์žˆ๋Š” ๊ฑฐ์ง€! ๐Ÿ˜Š

๐Ÿ’ก ์™œ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ์ค‘์š”ํ• ๊นŒ?

ํ˜„๋Œ€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ๋‹จ์ผ ํ”Œ๋žซํผ๋งŒ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ๊ฒฝ์Ÿ๋ ฅ์ด ๋–จ์–ด์ ธ. IoT ๋””๋ฐ”์ด์Šค, ๋ชจ๋ฐ”์ผ, ๋ฐ์Šคํฌํ†ฑ, ์„œ๋ฒ„๊นŒ์ง€ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ ๋™์ž‘ํ•ด์•ผ ํ•˜๋Š” ์‹œ๋Œ€๋‹ˆ๊นŒ. ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์€ ์„ ํƒ์ด ์•„๋‹Œ ํ•„์ˆ˜๊ฐ€ ๋˜์–ด๊ฐ€๊ณ  ์žˆ์–ด!

๐ŸŽจ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์˜ ๊ธฐ๋ณธ ๊ฐœ๋… ์ดํ•ดํ•˜๊ธฐ

๋จผ์ € ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ๋ญ”์ง€๋ถ€ํ„ฐ ํ™•์‹คํžˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€์ž. ํฌ๋กœ์Šค ์ปดํŒŒ์ผ(Cross Compilation)์€ ๋ง ๊ทธ๋Œ€๋กœ "๊ต์ฐจ ์ปดํŒŒ์ผ"์ด์•ผ. ์ฆ‰, ํ˜„์žฌ ์ž‘์—…ํ•˜๊ณ  ์žˆ๋Š” ํ”Œ๋žซํผ(ํ˜ธ์ŠคํŠธ)๊ณผ ๋‹ค๋ฅธ ํ”Œ๋žซํผ(ํƒ€๊ฒŸ)์„ ์œ„ํ•œ ์‹คํ–‰ ํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ๊ณผ์ •์ด์ง€.

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ? ๋„ˆ๊ฐ€ Windows PC์—์„œ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๋ผ์ฆˆ๋ฒ ๋ฆฌ ํŒŒ์ด(ARM ์•„ํ‚คํ…์ฒ˜)์—์„œ ๋Œ์•„๊ฐˆ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋ฉด? ์ผ๋ฐ˜์ ์ธ ์ปดํŒŒ์ผ์€ Windows์šฉ ์‹คํ–‰ ํŒŒ์ผ(.exe)์„ ๋งŒ๋“ค์ง€๋งŒ, ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉด ARM ์•„ํ‚คํ…์ฒ˜์šฉ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ๐ŸŽฏ

๐Ÿ“Œ ํ•ต์‹ฌ ์šฉ์–ด ์ •๋ฆฌ

ํ˜ธ์ŠคํŠธ(Host): ์ปดํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๋Š” ์‹œ์Šคํ…œ (์˜ˆ: ๋„ˆ์˜ ๊ฐœ๋ฐœ PC)
ํƒ€๊ฒŸ(Target): ์ปดํŒŒ์ผ๋œ ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋  ์‹œ์Šคํ…œ (์˜ˆ: ์ž„๋ฒ ๋””๋“œ ๋””๋ฐ”์ด์Šค)
๋นŒ๋“œ(Build): ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ์Šคํ…œ (๋Œ€๋ถ€๋ถ„ ํ˜ธ์ŠคํŠธ์™€ ๋™์ผ)
ํˆด์ฒด์ธ(Toolchain): ์ปดํŒŒ์ผ๋Ÿฌ, ๋ง์ปค, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ ๋นŒ๋“œ์— ํ•„์š”ํ•œ ๋„๊ตฌ ๋ชจ์Œ

ํ˜ธ์ŠคํŠธ ์‹œ์Šคํ…œ Windows PC x86_64 ์•„ํ‚คํ…์ฒ˜ ๐Ÿ’ป ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๋Ÿฌ GCC / Clang ํˆด์ฒด์ธ โš™๏ธ ํƒ€๊ฒŸ ์‹œ์Šคํ…œ Raspberry Pi ARM ์•„ํ‚คํ…์ฒ˜ ๐ŸŽฏ ์†Œ์Šค์ฝ”๋“œ ์‹คํ–‰ํŒŒ์ผ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ํ”„๋กœ์„ธ์Šค ํ•œ ํ”Œ๋žซํผ์—์„œ ๋‹ค๋ฅธ ํ”Œ๋žซํผ์šฉ ์‹คํ–‰ ํŒŒ์ผ ์ƒ์„ฑ

๐Ÿ› ๏ธ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์˜ ์‹ค์ „ ๋‹จ๊ณ„

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž. ์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‹จ๊ณ„๋ณ„๋กœ ์ฐจ๊ทผ์ฐจ๊ทผ ๋”ฐ๋ผ์˜ค๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ์–ด๋ ต์ง€ ์•Š์•„! ๐Ÿš€

Step 1: ํƒ€๊ฒŸ ํ”Œ๋žซํผ ๊ฒฐ์ •ํ•˜๊ธฐ ๐Ÿ“‹

๊ฐ€์žฅ ๋จผ์ € ํ•ด์•ผ ํ•  ์ผ์€ ์–ด๋–ค ํ”Œ๋žซํผ์„ ํƒ€๊ฒŸ์œผ๋กœ ํ•  ๊ฒƒ์ธ์ง€ ๋ช…ํ™•ํžˆ ์ •ํ•˜๋Š” ๊ฑฐ์•ผ. ๊ฐ ํ”Œ๋žซํผ๋งˆ๋‹ค ํ•„์š”ํ•œ ํˆด์ฒด์ธ๊ณผ ์„ค์ •์ด ๋‹ค๋ฅด๊ฑฐ๋“ .

๐ŸชŸ Windows ํƒ€๊ฒŸ

์•„ํ‚คํ…์ฒ˜: x86, x86_64, ARM64
์ฃผ์š” ์ปดํŒŒ์ผ๋Ÿฌ: MinGW, MSVC
ํŠน์ง•: DLL ์˜์กด์„ฑ ๊ด€๋ฆฌ ์ค‘์š”

๐Ÿง Linux ํƒ€๊ฒŸ

์•„ํ‚คํ…์ฒ˜: x86_64, ARM, ARM64
์ฃผ์š” ์ปดํŒŒ์ผ๋Ÿฌ: GCC, Clang
ํŠน์ง•: ๋‹ค์–‘ํ•œ ๋ฐฐํฌํŒ ๊ณ ๋ ค ํ•„์š”

๐ŸŽ macOS ํƒ€๊ฒŸ

์•„ํ‚คํ…์ฒ˜: x86_64, ARM64(M1/M2)
์ฃผ์š” ์ปดํŒŒ์ผ๋Ÿฌ: Clang (Apple Clang)
ํŠน์ง•: ์œ ๋‹ˆ๋ฒ„์„ค ๋ฐ”์ด๋„ˆ๋ฆฌ ์ง€์›

๐Ÿ“ฑ ๋ชจ๋ฐ”์ผ/์ž„๋ฒ ๋””๋“œ

์•„ํ‚คํ…์ฒ˜: ARM, ARM64, MIPS
์ฃผ์š” ์ปดํŒŒ์ผ๋Ÿฌ: ARM GCC, NDK
ํŠน์ง•: ๋ฆฌ์†Œ์Šค ์ œ์•ฝ ๊ณ ๋ ค

Step 2: ์ ์ ˆํ•œ ํˆด์ฒด์ธ ์„ ํƒ ๋ฐ ์„ค์น˜ ๐Ÿ”ง

ํˆด์ฒด์ธ์€ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์˜ ํ•ต์‹ฌ์ด์•ผ. ํƒ€๊ฒŸ ํ”Œ๋žซํผ์— ๋งž๋Š” ์ปดํŒŒ์ผ๋Ÿฌ, ๋ง์ปค, ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋˜์–ด ์žˆ์–ด์•ผ ํ•ด.

๐ŸŽฏ ์ฃผ์š” ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ํˆด์ฒด์ธ

1. GNU ํˆด์ฒด์ธ (GCC ๊ธฐ๋ฐ˜)

๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ์˜คํ”ˆ์†Œ์Šค ํˆด์ฒด์ธ์ด์•ผ. ๊ฑฐ์˜ ๋ชจ๋“  ํ”Œ๋žซํผ์„ ์ง€์›ํ•˜๊ณ , ์•ˆ์ •์„ฑ์ด ๊ฒ€์ฆ๋˜์–ด ์žˆ์–ด.

# ARM Linux์šฉ GCC ํˆด์ฒด์ธ ์„ค์น˜ (Ubuntu/Debian)
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf

# ARM64์šฉ ํˆด์ฒด์ธ
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

# Windows์šฉ MinGW ํˆด์ฒด์ธ
sudo apt-get install mingw-w64

2. LLVM/Clang ํˆด์ฒด์ธ

๋ชจ๋˜ํ•˜๊ณ  ๋น ๋ฅธ ์ปดํŒŒ์ผ ์†๋„๋ฅผ ์ž๋ž‘ํ•ด. ํŠนํžˆ macOS์™€ iOS ๊ฐœ๋ฐœ์—๋Š” ํ•„์ˆ˜์ ์ด์ง€.

# Clang ์„ค์น˜
sudo apt-get install clang

# ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ์‹œ ํƒ€๊ฒŸ ์ง€์ •
clang++ --target=arm-linux-gnueabihf -o output main.cpp

3. ํ”Œ๋žซํผ ํŠนํ™” ํˆด์ฒด์ธ

ํŠน์ • ํ”Œ๋žซํผ์„ ์œ„ํ•œ ์ „์šฉ ํˆด์ฒด์ธ๋„ ์žˆ์–ด. Android NDK, iOS SDK, Raspberry Pi ํˆด์ฒด์ธ ๋“ฑ์ด ๋Œ€ํ‘œ์ ์ด์•ผ.

๐Ÿ’ก Pro Tip: ํˆด์ฒด์ธ ๋ฒ„์ „ ๊ด€๋ฆฌ

์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๋™์‹œ์— ์ง„ํ–‰ํ•œ๋‹ค๋ฉด ํˆด์ฒด์ธ ๋ฒ„์ „ ๊ด€๋ฆฌ๊ฐ€ ์ •๋ง ์ค‘์š”ํ•ด! ํ”„๋กœ์ ํŠธ๋งˆ๋‹ค ์š”๊ตฌํ•˜๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ๋ฒ„์ „์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๊ฑฐ๋“ . Docker๋‚˜ ๊ฐ€์ƒํ™˜๊ฒฝ์„ ํ™œ์šฉํ•˜๋ฉด ๋ฒ„์ „ ์ถฉ๋Œ ์—†์ด ๊น”๋”ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๐Ÿณ

๐Ÿ—๏ธ CMake๋ฅผ ํ™œ์šฉํ•œ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๋นŒ๋“œ ์‹œ์Šคํ…œ

์ž, ์ด์ œ ์‹ค์ „์œผ๋กœ ๋“ค์–ด๊ฐ€๋ณด์ž! ํ˜„๋Œ€์ ์ธ C++ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” CMake๊ฐ€ ์‚ฌ์‹ค์ƒ ํ‘œ์ค€์ด์•ผ. CMake๋Š” ํ”Œ๋žซํผ ๋…๋ฆฝ์ ์ธ ๋นŒ๋“œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฑฐ๋“ . ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ๊ฐœ๋ฐœ์ž๋“ค์ด ํ”„๋กœ์ ํŠธ๋ฅผ ๊ณต์œ ํ•  ๋•Œ๋„ CMake๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์‰ฝ๊ฒŒ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽจ

๐Ÿ“ ๊ธฐ๋ณธ CMakeLists.txt ๊ตฌ์กฐ

cmake_minimum_required(VERSION 3.15)
project(CrossPlatformApp VERSION 1.0.0 LANGUAGES CXX)

# C++ ํ‘œ์ค€ ์„ค์ •
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# ์†Œ์Šค ํŒŒ์ผ ์ •์˜
set(SOURCES
    src/main.cpp
    src/utils.cpp
    src/platform_specific.cpp
)

# ์‹คํ–‰ ํŒŒ์ผ ์ƒ์„ฑ
add_executable(${PROJECT_NAME} ${SOURCES})

# ํ”Œ๋žซํผ๋ณ„ ์„ค์ •
if(WIN32)
    target_compile_definitions(${PROJECT_NAME} PRIVATE PLATFORM_WINDOWS)
elseif(APPLE)
    target_compile_definitions(${PROJECT_NAME} PRIVATE PLATFORM_MACOS)
elseif(UNIX)
    target_compile_definitions(${PROJECT_NAME} PRIVATE PLATFORM_LINUX)
endif()

# ์ปดํŒŒ์ผ ์˜ต์…˜
target_compile_options(${PROJECT_NAME} PRIVATE
    $<$<CXX_COMPILER_ID:MSVC>:/W4>
    $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -pedantic>
)

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ: ํ”Œ๋žซํผ๋ณ„ ์ฐจ์ด์ 

๊ฐ ํ”Œ๋žซํผ๋งˆ๋‹ค ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ฒฝ๋กœ ๊ตฌ๋ถ„์ž, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™•์žฅ์ž, ์‹คํ–‰ ํŒŒ์ผ ํ˜•์‹์ด ๋‹ฌ๋ผ. Windows๋Š” ์—ญ์Šฌ๋ž˜์‹œ(\)์™€ .dll, Linux๋Š” ์Šฌ๋ž˜์‹œ(/)์™€ .so, macOS๋Š” .dylib๋ฅผ ์‚ฌ์šฉํ•˜์ง€. CMake์˜ ํ”Œ๋žซํผ ๋ณ€์ˆ˜๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ด๋Ÿฐ ์ฐจ์ด๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด!

๐ŸŽฏ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ์œ„ํ•œ Toolchain ํŒŒ์ผ

CMake์—์„œ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ํ•˜๋ ค๋ฉด ํˆด์ฒด์ธ ํŒŒ์ผ์„ ์ž‘์„ฑํ•ด์•ผ ํ•ด. ์ด ํŒŒ์ผ์—๋Š” ํƒ€๊ฒŸ ์‹œ์Šคํ…œ ์ •๋ณด์™€ ์ปดํŒŒ์ผ๋Ÿฌ ๊ฒฝ๋กœ๊ฐ€ ๋‹ด๊ฒจ ์žˆ์–ด.

# arm-linux-toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

# ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๋Ÿฌ ๊ฒฝ๋กœ ์ง€์ •
set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabihf-g++)

# ํƒ€๊ฒŸ ์‹œ์Šคํ…œ์˜ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ
set(CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf)

# ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฒ€์ƒ‰ ๋ชจ๋“œ
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

# ์ถ”๊ฐ€ ์ปดํŒŒ์ผ ํ”Œ๋ž˜๊ทธ
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a -mfpu=neon")

์ด ํˆด์ฒด์ธ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•ด์„œ ๋นŒ๋“œํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹คํ–‰ํ•˜๋ฉด ๋ผ:

mkdir build-arm
cd build-arm
cmake -DCMAKE_TOOLCHAIN_FILE=../arm-linux-toolchain.cmake ..
make

๐Ÿš€ ์‹ค์ „ ์˜ˆ์ œ: ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ

์‹ค๋ฌด์—์„œ๋Š” ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์„ ํ•œ ๋ฒˆ์— ๋นŒ๋“œํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ๋งŽ์•„. ์ž๋™ํ™” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋‘๋ฉด ์ •๋ง ํŽธ๋ฆฌํ•˜์ง€!

#!/bin/bash
# build_all.sh - ๋ชจ๋“  ํ”Œ๋žซํผ ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ

PLATFORMS=("linux-x64" "linux-arm" "windows-x64" "macos-arm64")

for platform in "${PLATFORMS[@]}"; do
    echo "Building for $platform..."
    mkdir -p build-$platform
    cd build-$platform
    
    case $platform in
        "linux-x64")
            cmake ..
            ;;
        "linux-arm")
            cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/arm-linux.cmake ..
            ;;
        "windows-x64")
            cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/mingw-w64.cmake ..
            ;;
        "macos-arm64")
            cmake -DCMAKE_OSX_ARCHITECTURES=arm64 ..
            ;;
    esac
    
    make -j$(nproc)
    cd ..
done

echo "All builds completed!"

๐Ÿ” ํ”Œ๋žซํผ๋ณ„ ํŠน์ˆ˜ ๊ณ ๋ ค์‚ฌํ•ญ

๊ฐ ํ”Œ๋žซํผ๋งˆ๋‹ค ๋…ํŠนํ•œ ํŠน์„ฑ๊ณผ ์ œ์•ฝ์‚ฌํ•ญ์ด ์žˆ์–ด. ์ด๊ฑธ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ณ  ๋Œ€์‘ํ•ด์•ผ ์ง„์ •ํ•œ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋  ์ˆ˜ ์žˆ์ง€! ๐Ÿ˜Ž

๐ŸชŸ Windows ํ”Œ๋žซํผ ๋นŒ๋“œ

Windows๋Š” ๋‹ค๋ฅธ ํ”Œ๋žซํผ๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ ๋ช‡ ๊ฐ€์ง€ ๋…ํŠนํ•œ ์ ์ด ์žˆ์–ด:

1. ๋Ÿฐํƒ€์ž„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ ํƒ

MSVC๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋Ÿฐํƒ€์ž„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋งํฌ ๋ฐฉ์‹์„ ์„ ํƒํ•ด์•ผ ํ•ด. ์ •์  ๋งํฌ(/MT)์™€ ๋™์  ๋งํฌ(/MD) ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ณจ๋ผ์•ผ ํ•˜๋Š”๋ฐ, ์ด๊ฒŒ ํ”„๋กœ์ ํŠธ ์ „์ฒด์— ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ๋˜์–ด์•ผ ํ•ด.

# CMake์—์„œ ๋Ÿฐํƒ€์ž„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์ •
if(MSVC)
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()

2. DLL ์˜์กด์„ฑ ๊ด€๋ฆฌ

Windows์—์„œ๋Š” ์‹คํ–‰ ํŒŒ์ผ๊ณผ ๊ฐ™์€ ๋””๋ ‰ํ† ๋ฆฌ๋‚˜ ์‹œ์Šคํ…œ PATH์— DLL์ด ์žˆ์–ด์•ผ ํ•ด. ๋ฐฐํฌํ•  ๋•Œ ํ•„์š”ํ•œ DLL์„ ๋ชจ๋‘ ํฌํ•จ์‹œ์ผœ์•ผ ํ•œ๋‹ค๋Š” ์ , ์žŠ์ง€ ๋งˆ!

# ํ•„์š”ํ•œ DLL ๋ณต์‚ฌ (CMake)
if(WIN32)
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "${PROJECT_SOURCE_DIR}/libs/external.dll"
        $<TARGET_FILE_DIR:${PROJECT_NAME}>
    )
endif()

3. ๊ฒฝ๋กœ ๊ตฌ๋ถ„์ž ์ฒ˜๋ฆฌ

Windows๋Š” ๋ฐฑ์Šฌ๋ž˜์‹œ(\)๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, C++ ์ฝ”๋“œ์—์„œ๋Š” ์Šฌ๋ž˜์‹œ(/)๋„ ์ž˜ ์ž‘๋™ํ•ด. ํ•˜์ง€๋งŒ std::filesystem์„ ์‚ฌ์šฉํ•˜๋ฉด ํ”Œ๋žซํผ ๋…๋ฆฝ์ ์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์–ด!

#include <filesystem>
namespace fs = std::filesystem;

// ํ”Œ๋žซํผ ๋…๋ฆฝ์  ๊ฒฝ๋กœ ์ฒ˜๋ฆฌ
fs::path config_path = fs::current_path() / "config" / "settings.ini";
std::cout << config_path.string() << std::endl;

๐Ÿง Linux ํ”Œ๋žซํผ ๋นŒ๋“œ

Linux๋Š” ์˜คํ”ˆ์†Œ์Šค ์ƒํƒœ๊ณ„์˜ ์ค‘์‹ฌ์ด๋ผ ๊ฐœ๋ฐœ ๋„๊ตฌ๊ฐ€ ํ’๋ถ€ํ•˜์ง€๋งŒ, ๋ฐฐํฌํŒ๋งˆ๋‹ค ์ฐจ์ด๊ฐ€ ์žˆ์–ด ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ด.

1. ๋ฐฐํฌํŒ๋ณ„ ์ฐจ์ด

Ubuntu, Fedora, Arch Linux ๋“ฑ ๋ฐฐํฌํŒ๋งˆ๋‹ค ๊ธฐ๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „์ด ๋‹ฌ๋ผ. ์ •์  ๋งํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ AppImage ๊ฐ™์€ ํฌ๋งท์„ ํ™œ์šฉํ•˜๋ฉด ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์–ด.

# ์ •์  ๋งํฌ ์˜ต์…˜
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")

# ๋˜๋Š” ์™„์ „ ์ •์  ๋นŒ๋“œ
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")

2. RPATH ์„ค์ •

๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” RPATH๋ฅผ ์ œ๋Œ€๋กœ ์„ค์ •ํ•ด์•ผ ํ•ด. ์ด๊ฒŒ ์—†์œผ๋ฉด ์‹คํ–‰ ์‹œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐพ์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์–ด.

# CMake RPATH ์„ค์ •
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)

3. ๊ถŒํ•œ ๋ฐ ์‹คํ–‰ ์†์„ฑ

Linux์—์„œ๋Š” ์‹คํ–‰ ํŒŒ์ผ์— ์‹คํ–‰ ๊ถŒํ•œ์ด ํ•„์š”ํ•ด. ๋ฐฐํฌ ์‹œ ์ด ์ ์„ ๊ณ ๋ คํ•ด์•ผ ํ•˜์ง€.

# ์„ค์น˜ ์‹œ ์‹คํ–‰ ๊ถŒํ•œ ๋ถ€์—ฌ
install(TARGETS ${PROJECT_NAME}
    RUNTIME DESTINATION bin
    PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
                GROUP_EXECUTE GROUP_READ
                WORLD_EXECUTE WORLD_READ
)

๐ŸŽ macOS ํ”Œ๋žซํผ ๋นŒ๋“œ

macOS๋Š” ํŠนํžˆ M1/M2 ์นฉ ๋„์ž… ์ดํ›„ ARM64 ์•„ํ‚คํ…์ฒ˜ ์ง€์›์ด ์ค‘์š”ํ•ด์กŒ์–ด.

1. ์œ ๋‹ˆ๋ฒ„์„ค ๋ฐ”์ด๋„ˆ๋ฆฌ

Intel(x86_64)๊ณผ Apple Silicon(ARM64) ๋ชจ๋‘๋ฅผ ์ง€์›ํ•˜๋Š” ์œ ๋‹ˆ๋ฒ„์„ค ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.

# ์œ ๋‹ˆ๋ฒ„์„ค ๋ฐ”์ด๋„ˆ๋ฆฌ ๋นŒ๋“œ
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")

# ๋˜๋Š” ๊ฐœ๋ณ„ ๋นŒ๋“œ ํ›„ lipo๋กœ ํ•ฉ์น˜๊ธฐ
# lipo -create -output app_universal app_x86_64 app_arm64

2. ์ฝ”๋“œ ์„œ๋ช… ๋ฐ ๊ณต์ฆ

macOS 10.15 ์ด์ƒ์—์„œ๋Š” ์•ฑ ๋ฐฐํฌ ์‹œ ์ฝ”๋“œ ์„œ๋ช…๊ณผ ๊ณต์ฆ(Notarization)์ด ํ•„์š”ํ•ด. ์ด๊ฒŒ ์—†์œผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์‹คํ–‰ํ•  ๋•Œ ๊ฒฝ๊ณ ๊ฐ€ ๋œจ๊ฑฐ๋“ .

# ์ฝ”๋“œ ์„œ๋ช… (๊ฐœ๋ฐœ์ž ์ธ์ฆ์„œ ํ•„์š”)
codesign --force --deep --sign "Developer ID Application: Your Name" YourApp.app

# ๊ณต์ฆ ์ œ์ถœ
xcrun altool --notarize-app --file YourApp.zip \
    --primary-bundle-id "com.yourcompany.yourapp" \
    --username "your@email.com" --password "@keychain:AC_PASSWORD"

3. ํ”„๋ ˆ์ž„์›Œํฌ ์˜์กด์„ฑ

macOS๋Š” ์‹œ์Šคํ…œ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•ด. CMake์—์„œ ์ด๋ฅผ ์‰ฝ๊ฒŒ ๋งํฌํ•  ์ˆ˜ ์žˆ์–ด.

if(APPLE)
    find_library(COCOA_LIBRARY Cocoa)
    find_library(IOKIT_LIBRARY IOKit)
    target_link_libraries(${PROJECT_NAME} 
        ${COCOA_LIBRARY}
        ${IOKIT_LIBRARY}
    )
endif()

๐ŸŽฏ ์‹ค์ „ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์„ค๊ณ„

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ, ์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์กฐํ™”ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž! ์ข‹์€ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋Š” ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ณ , ์ƒˆ๋กœ์šด ํ”Œ๋žซํผ ์ถ”๊ฐ€๋„ ๊ฐ„ํŽธํ•˜๊ฒŒ ํ•ด์ค˜. ๐Ÿ—๏ธ

๐Ÿ“ ๊ถŒ์žฅ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

MyProject/
โ”œโ”€โ”€ CMakeLists.txt              # ๋ฃจํŠธ CMake ํŒŒ์ผ
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ LICENSE
โ”œโ”€โ”€ .gitignore
โ”‚
โ”œโ”€โ”€ src/                        # ์†Œ์Šค ์ฝ”๋“œ
โ”‚   โ”œโ”€โ”€ main.cpp
โ”‚   โ”œโ”€โ”€ core/                   # ํ•ต์‹ฌ ๋กœ์ง (ํ”Œ๋žซํผ ๋…๋ฆฝ์ )
โ”‚   โ”‚   โ”œโ”€โ”€ engine.cpp
โ”‚   โ”‚   โ””โ”€โ”€ engine.h
โ”‚   โ””โ”€โ”€ platform/               # ํ”Œ๋žซํผ๋ณ„ ๊ตฌํ˜„
โ”‚       โ”œโ”€โ”€ windows/
โ”‚       โ”‚   โ””โ”€โ”€ window_impl.cpp
โ”‚       โ”œโ”€โ”€ linux/
โ”‚       โ”‚   โ””โ”€โ”€ window_impl.cpp
โ”‚       โ””โ”€โ”€ macos/
โ”‚           โ””โ”€โ”€ window_impl.cpp
โ”‚
โ”œโ”€โ”€ include/                    # ๊ณต๊ฐœ ํ—ค๋” ํŒŒ์ผ
โ”‚   โ””โ”€โ”€ myproject/
โ”‚       โ””โ”€โ”€ api.h
โ”‚
โ”œโ”€โ”€ libs/                       # ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
โ”‚   โ”œโ”€โ”€ external_lib1/
โ”‚   โ””โ”€โ”€ external_lib2/
โ”‚
โ”œโ”€โ”€ toolchains/                 # ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ํˆด์ฒด์ธ ํŒŒ์ผ
โ”‚   โ”œโ”€โ”€ arm-linux.cmake
โ”‚   โ”œโ”€โ”€ mingw-w64.cmake
โ”‚   โ””โ”€โ”€ android-ndk.cmake
โ”‚
โ”œโ”€โ”€ scripts/                    # ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ
โ”‚   โ”œโ”€โ”€ build_all.sh
โ”‚   โ”œโ”€โ”€ package.sh
โ”‚   โ””โ”€โ”€ deploy.py
โ”‚
โ”œโ”€โ”€ tests/                      # ํ…Œ์ŠคํŠธ ์ฝ”๋“œ
โ”‚   โ”œโ”€โ”€ unit_tests/
โ”‚   โ””โ”€โ”€ integration_tests/
โ”‚
โ””โ”€โ”€ docs/                       # ๋ฌธ์„œ
    โ”œโ”€โ”€ build_instructions.md
    โ””โ”€โ”€ api_reference.md

๐Ÿ’ก ํ”Œ๋žซํผ ์ถ”์ƒํ™” ํŒจํ„ด

ํ”Œ๋žซํผ๋ณ„ ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•˜๋ ค๋ฉด ์ถ”์ƒํ™” ๋ ˆ์ด์–ด๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒŒ ์ข‹์•„. ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๊ณ , ๊ฐ ํ”Œ๋žซํผ์—์„œ ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์‹์ด์ง€.

// platform_interface.h
class IPlatformWindow {
public:
    virtual ~IPlatformWindow() = default;
    virtual bool create(int width, int height) = 0;
    virtual void show() = 0;
    virtual void update() = 0;
};

// ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜
std::unique_ptr<IPlatformWindow> createPlatformWindow();

// windows_window.cpp
#ifdef _WIN32
class WindowsWindow : public IPlatformWindow {
    // Windows ํŠนํ™” ๊ตฌํ˜„
};

std::unique_ptr<IPlatformWindow> createPlatformWindow() {
    return std::make_unique<WindowsWindow>();
}
#endif

// linux_window.cpp
#ifdef __linux__
class LinuxWindow : public IPlatformWindow {
    // Linux ํŠนํ™” ๊ตฌํ˜„
};

std::unique_ptr<IPlatformWindow> createPlatformWindow() {
    return std::make_unique<LinuxWindow>();
}
#endif

๐Ÿ”ง ์กฐ๊ฑด๋ถ€ ์ปดํŒŒ์ผ ํ™œ์šฉํ•˜๊ธฐ

ํ”Œ๋žซํผ๋ณ„๋กœ ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•  ๋•Œ๋Š” ์ „์ฒ˜๋ฆฌ๊ธฐ ๋งคํฌ๋กœ๋ฅผ ํ™œ์šฉํ•ด. ํ•˜์ง€๋งŒ ๋„ˆ๋ฌด ๋‚จ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•ด์ง€๋‹ˆ ์ฃผ์˜ํ•ด์•ผ ํ•ด!

// platform_detection.h
#ifndef PLATFORM_DETECTION_H
#define PLATFORM_DETECTION_H

// ํ”Œ๋žซํผ ๊ฐ์ง€
#if defined(_WIN32) || defined(_WIN64)
    #define PLATFORM_WINDOWS
    #ifdef _WIN64
        #define PLATFORM_WINDOWS_64
    #else
        #define PLATFORM_WINDOWS_32
    #endif
#elif defined(__APPLE__) || defined(__MACH__)
    #include <TargetConditionals.h>
    #if TARGET_OS_MAC
        #define PLATFORM_MACOS
    #elif TARGET_OS_IPHONE
        #define PLATFORM_IOS
    #endif
#elif defined(__linux__)
    #define PLATFORM_LINUX
    #if defined(__ANDROID__)
        #define PLATFORM_ANDROID
    #endif
#elif defined(__unix__)
    #define PLATFORM_UNIX
#endif

// ์•„ํ‚คํ…์ฒ˜ ๊ฐ์ง€
#if defined(__x86_64__) || defined(_M_X64)
    #define ARCH_X64
#elif defined(__i386) || defined(_M_IX86)
    #define ARCH_X86
#elif defined(__aarch64__) || defined(_M_ARM64)
    #define ARCH_ARM64
#elif defined(__arm__) || defined(_M_ARM)
    #define ARCH_ARM
#endif

// ์ปดํŒŒ์ผ๋Ÿฌ ๊ฐ์ง€
#if defined(__clang__)
    #define COMPILER_CLANG
#elif defined(__GNUC__) || defined(__GNUG__)
    #define COMPILER_GCC
#elif defined(_MSC_VER)
    #define COMPILER_MSVC
#endif

#endif // PLATFORM_DETECTION_H

์ด์ œ ์ด ํ—ค๋”๋ฅผ ํฌํ•จํ•˜๋ฉด ์–ด๋””์„œ๋“  ํ”Œ๋žซํผ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด:

#include "platform_detection.h"

void initializeSystem() {
#ifdef PLATFORM_WINDOWS
    // Windows ์ดˆ๊ธฐํ™”
    initWinSock();
#elif defined(PLATFORM_LINUX)
    // Linux ์ดˆ๊ธฐํ™”
    initPosixSignals();
#elif defined(PLATFORM_MACOS)
    // macOS ์ดˆ๊ธฐํ™”
    initCocoaApp();
#endif
}

๐Ÿ“ฆ ์˜์กด์„ฑ ๊ด€๋ฆฌ์™€ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €

ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๊ฐœ๋ฐœ์—์„œ ๊ฐ€์žฅ ๊ณจ์น˜ ์•„ํ”ˆ ๋ถ€๋ถ„ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ ์˜์กด์„ฑ ๊ด€๋ฆฌ์•ผ. ๊ฐ ํ”Œ๋žซํผ๋งˆ๋‹ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋”ฐ๋กœ ๋นŒ๋“œํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ฑด ์ •๋ง ๋ฒˆ๊ฑฐ๋กœ์šด ์ผ์ด๊ฑฐ๋“ . ๋‹คํ–‰ํžˆ ํ˜„๋Œ€์ ์ธ ๋„๊ตฌ๋“ค์ด ์ด ๋ฌธ์ œ๋ฅผ ๋งŽ์ด ํ•ด๊ฒฐํ•ด์ค˜! ๐ŸŽ

๐Ÿ”น Conan ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €

Conan์€ C/C++๋ฅผ ์œ„ํ•œ ๊ฐ•๋ ฅํ•œ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €์•ผ. Python์˜ pip๋‚˜ Node.js์˜ npm์ฒ˜๋Ÿผ ์˜์กด์„ฑ์„ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜.

์„ค์น˜ ๋ฐ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•:

# Conan ์„ค์น˜
pip install conan

# ํ”„๋กœํŒŒ์ผ ๊ฐ์ง€
conan profile detect --force

# conanfile.txt ์ž‘์„ฑ
[requires]
boost/1.81.0
openssl/3.1.0
fmt/9.1.0

[generators]
CMakeDeps
CMakeToolchain

[options]
boost:shared=False
openssl:shared=True

CMakeLists.txt์—์„œ Conan ํ†ตํ•ฉ:

cmake_minimum_required(VERSION 3.15)
project(MyProject)

# Conan์œผ๋กœ ์„ค์น˜ํ•œ ์˜์กด์„ฑ ์ฐพ๊ธฐ
find_package(Boost REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(fmt REQUIRED)

add_executable(myapp main.cpp)

target_link_libraries(myapp
    Boost::boost
    OpenSSL::SSL
    fmt::fmt
)

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ์‹œ Conan ํ”„๋กœํŒŒ์ผ ์‚ฌ์šฉ:

# arm-linux-profile
[settings]
os=Linux
arch=armv7
compiler=gcc
compiler.version=11
compiler.libcxx=libstdc++11
build_type=Release

[buildenv]
CC=arm-linux-gnueabihf-gcc
CXX=arm-linux-gnueabihf-g++

# ํ”„๋กœํŒŒ์ผ ์‚ฌ์šฉํ•ด์„œ ์˜์กด์„ฑ ์„ค์น˜
conan install . --profile=arm-linux-profile --build=missing

๐Ÿ”น vcpkg ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €

Microsoft๊ฐ€ ๋งŒ๋“  vcpkg๋„ ํ›Œ๋ฅญํ•œ ์„ ํƒ์ง€์•ผ. ํŠนํžˆ Windows ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ ์นœ์ˆ™ํ•˜๊ณ , CMake์™€์˜ ํ†ตํ•ฉ์ด ๋งค๋„๋Ÿฌ์›Œ.

# vcpkg ์„ค์น˜ (Linux/macOS)
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh

# ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
./vcpkg install boost:x64-linux
./vcpkg install openssl:x64-linux
./vcpkg install fmt:x64-linux

# ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์šฉ ํŠธ๋ฆฌํ”Œ๋ ›
./vcpkg install boost:arm-linux
./vcpkg install boost:x64-windows
./vcpkg install boost:arm64-osx

CMake์—์„œ vcpkg ์‚ฌ์šฉ:

cmake -B build -S . \
    -DCMAKE_TOOLCHAIN_FILE=[vcpkg root]/scripts/buildsystems/vcpkg.cmake

# ๋˜๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
export CMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake

โš ๏ธ ์˜์กด์„ฑ ๊ด€๋ฆฌ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

1. ๋ฒ„์ „ ๊ณ ์ •: ์˜์กด์„ฑ ๋ฒ„์ „์„ ๋ช…ํ™•ํžˆ ์ง€์ •ํ•ด์„œ ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋นŒ๋“œ ๋ณด์žฅ
2. ์ตœ์†Œํ™”: ์ •๋ง ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ์‚ฌ์šฉ (๋นŒ๋“œ ์‹œ๊ฐ„๊ณผ ๋ฐ”์ด๋„ˆ๋ฆฌ ํฌ๊ธฐ ๊ณ ๋ ค)
3. ๋ผ์ด์„ ์Šค ํ™•์ธ: ์ƒ์šฉ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด ๊ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ผ์ด์„ ์Šค ๊ผญ ์ฒดํฌ
4. ๋ณด์•ˆ ์—…๋ฐ์ดํŠธ: ์ •๊ธฐ์ ์œผ๋กœ ์˜์กด์„ฑ ์—…๋ฐ์ดํŠธํ•ด์„œ ๋ณด์•ˆ ์ทจ์•ฝ์  ํŒจ์น˜

๐Ÿงช ํฌ๋กœ์Šค ํ”Œ๋žซํผ ํ…Œ์ŠคํŒ… ์ „๋žต

์ฝ”๋“œ๋ฅผ ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์—์„œ ๋นŒ๋“œํ–ˆ๋‹ค๊ณ  ๋์ด ์•„๋‹ˆ์•ผ. ๊ฐ ํ”Œ๋žซํผ์—์„œ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒŒ ์ •๋ง ์ค‘์š”ํ•ด! ๐Ÿ”ฌ

๐ŸŽฏ ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๊ตฌ์ถ•

1. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (Unit Testing)

Google Test๋‚˜ Catch2 ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ”Œ๋žซํผ ๋…๋ฆฝ์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด.

// CMakeLists.txt์— ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
enable_testing()

# Google Test ์ถ”๊ฐ€
include(FetchContent)
FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG release-1.12.1
)
FetchContent_MakeAvailable(googletest)

# ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํŒŒ์ผ
add_executable(unit_tests
    tests/test_core.cpp
    tests/test_utils.cpp
)

target_link_libraries(unit_tests
    gtest_main
    myproject_lib
)

add_test(NAME UnitTests COMMAND unit_tests)

ํ”Œ๋žซํผ๋ณ„ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค:

#include <gtest/gtest.h>
#include "platform_detection.h"

TEST(PlatformTest, FileSystemOperations) {
    // ํ”Œ๋žซํผ ๋…๋ฆฝ์  ํ…Œ์ŠคํŠธ
    auto path = std::filesystem::temp_directory_path();
    EXPECT_TRUE(std::filesystem::exists(path));
}

#ifdef PLATFORM_WINDOWS
TEST(WindowsTest, RegistryAccess) {
    // Windows ์ „์šฉ ํ…Œ์ŠคํŠธ
    // ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ ‘๊ทผ ํ…Œ์ŠคํŠธ
}
#endif

#ifdef PLATFORM_LINUX
TEST(LinuxTest, ProcFileSystem) {
    // Linux ์ „์šฉ ํ…Œ์ŠคํŠธ
    EXPECT_TRUE(std::filesystem::exists("/proc/cpuinfo"));
}
#endif

2. CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•

GitHub Actions, GitLab CI, Jenkins ๋“ฑ์„ ํ™œ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์—์„œ ์ž๋™์œผ๋กœ ๋นŒ๋“œํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์–ด.

# .github/workflows/build.yml
name: Multi-Platform Build

on: [push, pull_request]

jobs:
  build-linux:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install dependencies
        run: sudo apt-get install -y cmake g++
      - name: Build
        run: |
          mkdir build && cd build
          cmake ..
          make -j$(nproc)
      - name: Test
        run: cd build && ctest --output-on-failure

  build-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build
        run: |
          mkdir build
          cd build
          cmake ..
          cmake --build . --config Release
      - name: Test
        run: cd build && ctest -C Release --output-on-failure

  build-macos:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build
        run: |
          mkdir build && cd build
          cmake ..
          make -j$(sysctl -n hw.ncpu)
      - name: Test
        run: cd build && ctest --output-on-failure

  build-cross-arm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install ARM toolchain
        run: sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
      - name: Cross compile
        run: |
          mkdir build-arm && cd build-arm
          cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/arm-linux.cmake ..
          make -j$(nproc)

๐Ÿ’ก ์‹ค์ œ ํ•˜๋“œ์›จ์–ด ํ…Œ์ŠคํŠธ์˜ ์ค‘์š”์„ฑ

์—๋ฎฌ๋ ˆ์ดํ„ฐ๋‚˜ ๊ฐ€์ƒ ํ™˜๊ฒฝ์—์„œ์˜ ํ…Œ์ŠคํŠธ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ, ์‹ค์ œ ํƒ€๊ฒŸ ํ•˜๋“œ์›จ์–ด์—์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ๋„ ๊ผญ ํ•„์š”ํ•ด! ํŠนํžˆ ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ์ด๋‚˜ ๋ชจ๋ฐ”์ผ ๊ธฐ๊ธฐ์˜ ๊ฒฝ์šฐ, ์„ฑ๋Šฅ์ด๋‚˜ ํ•˜๋“œ์›จ์–ด ํŠน์„ฑ์ด ํฌ๊ฒŒ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๊ฐ€๋Šฅํ•˜๋ฉด ๊ฐ ํ”Œ๋žซํผ์˜ ์‹ค์ œ ๊ธฐ๊ธฐ๋ฅผ ํ™•๋ณดํ•ด์„œ ์ตœ์ข… ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฒŒ ์ข‹์•„. ๐ŸŽฏ

๐Ÿš€ ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ํ”Œ๋žซํผ๋ณ„ ํŠœ๋‹

๊ฐ™์€ ์ฝ”๋“œ๋ผ๋„ ํ”Œ๋žซํผ๋งˆ๋‹ค ์„ฑ๋Šฅ์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์–ด. ๊ฐ ํ”Œ๋žซํผ์˜ ํŠน์„ฑ์„ ์ดํ•ดํ•˜๊ณ  ์ตœ์ ํ™”ํ•˜๋ฉด ํ›จ์”ฌ ๋” ๋‚˜์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์ง€! โšก

๐ŸŽฏ ์ปดํŒŒ์ผ๋Ÿฌ ์ตœ์ ํ™” ์˜ต์…˜

๊ฐ ์ปดํŒŒ์ผ๋Ÿฌ๋งˆ๋‹ค ์ตœ์ ํ™” ์˜ต์…˜์ด ์กฐ๊ธˆ์”ฉ ๋‹ฌ๋ผ. ํ”Œ๋žซํผ๋ณ„๋กœ ์ ์ ˆํ•œ ์˜ต์…˜์„ ์„ค์ •ํ•ด์ฃผ๋Š” ๊ฒŒ ์ค‘์š”ํ•ด.

# CMake์—์„œ ํ”Œ๋žซํผ๋ณ„ ์ตœ์ ํ™” ์„ค์ •
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    # GCC/Clang ์ตœ์ ํ™”
    set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -mtune=native -flto")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math")
    
    # ARM ํŠนํ™” ์ตœ์ ํ™”
    if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -mfloat-abi=hard")
    endif()
    
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
    # MSVC ์ตœ์ ํ™”
    set(CMAKE_CXX_FLAGS_RELEASE "/O2 /GL /arch:AVX2")
    set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/LTCG")
endif()

# ๋””๋ฒ„๊ทธ ๋นŒ๋“œ ์ตœ์ ํ™” (๋””๋ฒ„๊น… ๊ฐ€๋Šฅํ•˜๋ฉด์„œ๋„ ์ ๋‹นํ•œ ์†๋„)
set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g")

๐Ÿ”ฅ GCC/Clang ์ตœ์ ํ™” ๋ ˆ๋ฒจ

-O0: ์ตœ์ ํ™” ์—†์Œ (๋””๋ฒ„๊น…์šฉ)
-O1: ๊ธฐ๋ณธ ์ตœ์ ํ™”
-O2: ๊ถŒ์žฅ ์ตœ์ ํ™” (๋Œ€๋ถ€๋ถ„ ์‚ฌ์šฉ)
-O3: ๊ณต๊ฒฉ์  ์ตœ์ ํ™”
-Os: ํฌ๊ธฐ ์ตœ์ ํ™”
-Ofast: ์ตœ๋Œ€ ์†๋„ (ํ‘œ์ค€ ์œ„๋ฐ˜ ๊ฐ€๋Šฅ)

โšก MSVC ์ตœ์ ํ™” ์˜ต์…˜

/Od: ์ตœ์ ํ™” ๋น„ํ™œ์„ฑํ™”
/O1: ํฌ๊ธฐ ์ตœ์†Œํ™”
/O2: ์†๋„ ์ตœ๋Œ€ํ™” (๊ถŒ์žฅ)
/Ox: ์ „์ฒด ์ตœ์ ํ™”
/GL: ์ „์ฒด ํ”„๋กœ๊ทธ๋žจ ์ตœ์ ํ™”
/arch:AVX2: SIMD ๋ช…๋ น์–ด ์‚ฌ์šฉ

๐Ÿ” ํ”„๋กœํŒŒ์ผ๋ง๊ณผ ๋ณ‘๋ชฉ ์ง€์  ์ฐพ๊ธฐ

์ตœ์ ํ™”์˜ ์ฒซ ๋‹จ๊ณ„๋Š” ์ธก์ •์ด์•ผ. ์–ด๋””๊ฐ€ ๋А๋ฆฐ์ง€ ์•Œ์•„์•ผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ!

ํ”Œ๋žซํผ๋ณ„ ํ”„๋กœํŒŒ์ผ๋ง ๋„๊ตฌ:

ํ”Œ๋žซํผ ํ”„๋กœํŒŒ์ผ๋Ÿฌ ํŠน์ง•
Linux perf, Valgrind, gprof ๋ฌด๋ฃŒ, ๊ฐ•๋ ฅํ•œ ๋ถ„์„ ๊ธฐ๋Šฅ
Windows Visual Studio Profiler, Intel VTune GUI ๊ธฐ๋ฐ˜, ์ง๊ด€์ 
macOS Instruments, Xcode Profiler ํ†ตํ•ฉ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
ํฌ๋กœ์Šค ํ”Œ๋žซํผ Tracy, Optick ์‹ค์‹œ๊ฐ„ ํ”„๋กœํŒŒ์ผ๋ง

๊ฐ„๋‹จํ•œ ํ”„๋กœํŒŒ์ผ๋ง ์ฝ”๋“œ ์˜ˆ์ œ:

#include <chrono>
#include <iostream>

class Timer {
    std::chrono::high_resolution_clock::time_point start;
    const char* name;
public:
    Timer(const char* n) : name(n) {
        start = std::chrono::high_resolution_clock::now();
    }
    
    ~Timer() {
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        std::cout << name << ": " << duration.count() << " ฮผs\n";
    }
};

void criticalFunction() {
    Timer t("criticalFunction");
    // ์ธก์ •ํ•  ์ฝ”๋“œ
    for(int i = 0; i < 1000000; ++i) {
        // ์ž‘์—… ์ˆ˜ํ–‰
    }
}

๐Ÿ’พ ๋ฉ”๋ชจ๋ฆฌ ์ •๋ ฌ๊ณผ ์บ์‹œ ์ตœ์ ํ™”

ํ”Œ๋žซํผ๋งˆ๋‹ค ๋ฉ”๋ชจ๋ฆฌ ์ •๋ ฌ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ARM ๊ฐ™์€ ์•„ํ‚คํ…์ฒ˜์—์„œ๋Š” ์ •๋ ฌ๋˜์ง€ ์•Š์€ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด ์„ฑ๋Šฅ ์ €ํ•˜๋‚˜ ํฌ๋ž˜์‹œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์–ด.

// ๋ฉ”๋ชจ๋ฆฌ ์ •๋ ฌ ์ง€์ •
struct alignas(16) AlignedData {
    float x, y, z, w;
};

// ์บ์‹œ ๋ผ์ธ ํฌ๊ธฐ ๊ณ ๋ ค (๋ณดํ†ต 64๋ฐ”์ดํŠธ)
struct alignas(64) CacheAligned {
    int data[16];
};

// ์ปดํŒŒ์ผ๋Ÿฌ๋ณ„ ์ •๋ ฌ ์†์„ฑ
#ifdef _MSC_VER
    #define ALIGN(n) __declspec(align(n))
#else
    #define ALIGN(n) __attribute__((aligned(n)))
#endif

ALIGN(32) float simd_data[8];

SIMD ์ตœ์ ํ™”:

ํ”Œ๋žซํผ๋ณ„ SIMD ๋ช…๋ น์–ด๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด.

#include <immintrin.h>  // Intel SSE/AVX

void vectorAdd(float* a, float* b, float* result, size_t size) {
#if defined(__AVX__)
    // AVX ์‚ฌ์šฉ ๊ฐ€๋Šฅ (8๊ฐœ float ๋™์‹œ ์ฒ˜๋ฆฌ)
    for(size_t i = 0; i < size; i += 8) {
        __m256 va = _mm256_load_ps(&a[i]);
        __m256 vb = _mm256_load_ps(&b[i]);
        __m256 vr = _mm256_add_ps(va, vb);
        _mm256_store_ps(&result[i], vr);
    }
#elif defined(__ARM_NEON)
    // ARM NEON ์‚ฌ์šฉ (4๊ฐœ float ๋™์‹œ ์ฒ˜๋ฆฌ)
    for(size_t i = 0; i < size; i += 4) {
        float32x4_t va = vld1q_f32(&a[i]);
        float32x4_t vb = vld1q_f32(&b[i]);
        float32x4_t vr = vaddq_f32(va, vb);
        vst1q_f32(&result[i], vr);
    }
#else
    // ์ผ๋ฐ˜ ์Šค์นผ๋ผ ์—ฐ์‚ฐ
    for(size_t i = 0; i < size; ++i) {
        result[i] = a[i] + b[i];
    }
#endif
}

๐Ÿ“ฑ ๋ชจ๋ฐ”์ผ ๋ฐ ์ž„๋ฒ ๋””๋“œ ํ”Œ๋žซํผ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ

์ด์ œ ์ข€ ๋” ํŠน์ˆ˜ํ•œ ์ผ€์ด์Šค๋ฅผ ์‚ดํŽด๋ณด์ž. ๋ชจ๋ฐ”์ผ์ด๋‚˜ ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ์€ ๋ฐ์Šคํฌํ†ฑ๊ณผ๋Š” ๋‹ค๋ฅธ ์ ‘๊ทผ์ด ํ•„์š”ํ•ด! ๐Ÿ“ฒ

๐Ÿค– Android NDK ํฌ๋กœ์Šค ์ปดํŒŒ์ผ

Android ์•ฑ์—์„œ C++ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด NDK(Native Development Kit)๊ฐ€ ํ•„์š”ํ•ด.

1. NDK ์„ค์น˜ ๋ฐ ํ™˜๊ฒฝ ์„ค์ •

# Android Studio๋ฅผ ํ†ตํ•ด NDK ์„ค์น˜ํ•˜๊ฑฐ๋‚˜
# ์ง์ ‘ ๋‹ค์šด๋กœ๋“œ: https://developer.android.com/ndk/downloads

# ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •
export ANDROID_NDK_HOME=/path/to/android-ndk
export PATH=$PATH:$ANDROID_NDK_HOME

2. CMake ํˆด์ฒด์ธ ํŒŒ์ผ ์‚ฌ์šฉ

# android-toolchain.cmake (NDK์— ํฌํ•จ๋จ)
cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
      -DANDROID_ABI=arm64-v8a \
      -DANDROID_PLATFORM=android-24 \
      -DANDROID_STL=c++_shared \
      -B build-android

# ์ง€์›๋˜๋Š” ABI
# - armeabi-v7a (32-bit ARM)
# - arm64-v8a (64-bit ARM)
# - x86 (32-bit Intel)
# - x86_64 (64-bit Intel)

3. Gradle ํ†ตํ•ฉ

// app/build.gradle
android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++17 -frtti -fexceptions"
                abiFilters 'arm64-v8a', 'armeabi-v7a'
            }
        }
    }
    
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.22.1"
        }
    }
}

๐ŸŽ iOS ํฌ๋กœ์Šค ์ปดํŒŒ์ผ

iOS ๊ฐœ๋ฐœ์€ macOS์—์„œ๋งŒ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ๊ฐœ๋…์€ ์—ฌ์ „ํžˆ ์ ์šฉ๋ผ. ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ(x86_64)์™€ ์‹ค์ œ ๊ธฐ๊ธฐ(ARM64)๊ฐ€ ๋‹ค๋ฅธ ์•„ํ‚คํ…์ฒ˜๋‹ˆ๊นŒ!

# iOS ํˆด์ฒด์ธ ํŒŒ์ผ (ios.toolchain.cmake)
set(CMAKE_SYSTEM_NAME iOS)
set(CMAKE_OSX_SYSROOT iphoneos)
set(CMAKE_OSX_ARCHITECTURES arm64)

# ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์šฉ
# set(CMAKE_OSX_SYSROOT iphonesimulator)
# set(CMAKE_OSX_ARCHITECTURES x86_64)

# ๋นŒ๋“œ
cmake -DCMAKE_TOOLCHAIN_FILE=ios.toolchain.cmake \
      -GXcode \
      -B build-ios

์œ ๋‹ˆ๋ฒ„์„ค ํ”„๋ ˆ์ž„์›Œํฌ ์ƒ์„ฑ:

# ๊ธฐ๊ธฐ์šฉ ๋นŒ๋“œ
cmake --build build-ios --config Release -- -sdk iphoneos

# ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์šฉ ๋นŒ๋“œ
cmake --build build-ios-sim --config Release -- -sdk iphonesimulator

# XCFramework๋กœ ํ•ฉ์น˜๊ธฐ
xcodebuild -create-xcframework \
    -framework build-ios/Release-iphoneos/MyLib.framework \
    -framework build-ios-sim/Release-iphonesimulator/MyLib.framework \
    -output MyLib.xcframework

๐Ÿ”Œ ์ž„๋ฒ ๋””๋“œ Linux (Raspberry Pi, BeagleBone ๋“ฑ)

์ž„๋ฒ ๋””๋“œ Linux ์‹œ์Šคํ…œ์€ ๋ฆฌ์†Œ์Šค๊ฐ€ ์ œํ•œ์ ์ด๋ผ ์ตœ์ ํ™”๊ฐ€ ํŠนํžˆ ์ค‘์š”ํ•ด!

# Raspberry Pi 4 (ARM Cortex-A72) ํˆด์ฒด์ธ
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

# Raspberry Pi ํŠนํ™” ์ตœ์ ํ™”
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=cortex-a72 -mfpu=neon-fp-armv8")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -ffast-math")

# ์ •์  ๋งํฌ (์˜์กด์„ฑ ์ตœ์†Œํ™”)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")

ํฌ๊ธฐ ์ตœ์ ํ™” (์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ์—์„œ ์ค‘์š”!):

# ๋ถˆํ•„์š”ํ•œ ์‹ฌ๋ณผ ์ œ๊ฑฐ
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")

# ๋งํฌ ํƒ€์ž„ ์ตœ์ ํ™”
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)

# ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜ ์ œ๊ฑฐ
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")

# ๊ฒฐ๊ณผ ํ™•์ธ
# arm-linux-gnueabihf-size myapp
# arm-linux-gnueabihf-strip myapp  # ์ถ”๊ฐ€ ํฌ๊ธฐ ๊ฐ์†Œ

โš ๏ธ ์ž„๋ฒ ๋””๋“œ ๊ฐœ๋ฐœ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

1. ๋ฉ”๋ชจ๋ฆฌ ์ œ์•ฝ: ๋™์  ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์ตœ์†Œํ™”, ์Šคํƒ ํฌ๊ธฐ ๊ณ ๋ ค
2. ์ „๋ ฅ ์†Œ๋น„: ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ ์ค„์ด๊ธฐ, ์Šฌ๋ฆฝ ๋ชจ๋“œ ํ™œ์šฉ
3. ์‹ค์‹œ๊ฐ„์„ฑ: ์‹œ๊ฐ„ ์ œ์•ฝ์ด ์žˆ๋‹ค๋ฉด RTOS ๊ณ ๋ ค
4. ํ•˜๋“œ์›จ์–ด ์ ‘๊ทผ: ๋ฉ”๋ชจ๋ฆฌ ๋งต I/O, ์ธํ„ฐ๋ŸฝํŠธ ์ฒ˜๋ฆฌ ํ•„์š”
5. ๋””๋ฒ„๊น…: ์›๊ฒฉ ๋””๋ฒ„๊น… ํ™˜๊ฒฝ ๊ตฌ์ถ• (GDB server ๋“ฑ)

๐Ÿ” ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๊ฐœ๋ฐœ์—์„œ ๋ณด์•ˆ๋„ ์ •๋ง ์ค‘์š”ํ•ด. ํ”Œ๋žซํผ๋งˆ๋‹ค ๋ณด์•ˆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ๋‹ค๋ฅด๋‹ˆ๊นŒ ๊ฐ๊ฐ์— ๋งž๊ฒŒ ๋Œ€์‘ํ•ด์•ผ ํ•ด! ๐Ÿ›ก๏ธ

๐Ÿ”’ ํ”Œ๋žซํผ๋ณ„ ๋ณด์•ˆ ๊ธฐ๋Šฅ

1. ์ฝ”๋“œ ์„œ๋ช… (Code Signing)

// Windows: Authenticode
signtool sign /f certificate.pfx /p password /t http://timestamp.server.com myapp.exe

// macOS: codesign
codesign --force --deep --sign "Developer ID Application: Your Name" MyApp.app

// Linux: AppImage ์„œ๋ช…
gpg --detach-sign MyApp.AppImage

2. ๋ฉ”๋ชจ๋ฆฌ ๋ณดํ˜ธ ๊ธฐ๋ฒ•

// CMake์—์„œ ๋ณด์•ˆ ํ”Œ๋ž˜๊ทธ ํ™œ์„ฑํ™”
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    # Stack canary (์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๊ฐ์ง€)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-strong")
    
    # Position Independent Executable
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
    
    # RELRO (Relocation Read-Only)
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro,-z,now")
    
    # NX bit (์‹คํ–‰ ๋ฐฉ์ง€)
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,noexecstack")
endif()

if(MSVC)
    # Control Flow Guard
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /guard:cf")
    
    # Data Execution Prevention
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /NXCOMPAT")
    
    # Address Space Layout Randomization
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DYNAMICBASE")
endif()

3. ์•ˆ์ „ํ•œ ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ

#include <string_view>
#include <span>

// ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐฉ์ง€
void safeStringCopy(char* dest, size_t destSize, const char* src) {
#ifdef _MSC_VER
    strcpy_s(dest, destSize, src);
#else
    strncpy(dest, src, destSize - 1);
    dest[destSize - 1] = '\0';
#endif
}

// ํ˜„๋Œ€์  C++ ๋ฐฉ์‹ (๋” ์•ˆ์ „)
void processData(std::string_view data) {
    // string_view๋Š” ๋ณต์‚ฌ ์—†์ด ์•ˆ์ „ํ•˜๊ฒŒ ๋ฌธ์ž์—ด ์ฐธ์กฐ
}

void processBuffer(std::span<const uint8_t> buffer) {
    // span์€ ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ๋ฅผ ์ œ๊ณต
    if(buffer.size() < 10) return;
    // ์•ˆ์ „ํ•œ ์ ‘๊ทผ
}

๐ŸŽจ ์‹ค์ „ ํ”„๋กœ์ ํŠธ: ํฌ๋กœ์Šค ํ”Œ๋žซํผ ํŒŒ์ผ ์•”ํ˜ธํ™” ๋„๊ตฌ

์ด๋ก ๋งŒ ๋ฐฐ์šฐ๋ฉด ์žฌ๋ฏธ์—†์œผ๋‹ˆ, ์‹ค์ œ๋กœ ๋™์ž‘ํ•˜๋Š” ํฌ๋กœ์Šค ํ”Œ๋žซํผ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ๊ฐ„๋‹จํ•œ ํŒŒ์ผ ์•”ํ˜ธํ™” ๋„๊ตฌ๋ฅผ ์˜ˆ์ œ๋กœ ์‚ดํŽด๋ณผ๊ฒŒ. ๐Ÿ”

๐Ÿ“‹ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

FileCryptor/
โ”œโ”€โ”€ CMakeLists.txt
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ main.cpp
โ”‚   โ”œโ”€โ”€ crypto/
โ”‚   โ”‚   โ”œโ”€โ”€ aes.cpp
โ”‚   โ”‚   โ””โ”€โ”€ aes.h
โ”‚   โ””โ”€โ”€ platform/
โ”‚       โ”œโ”€โ”€ file_io.h
โ”‚       โ”œโ”€โ”€ windows_file.cpp
โ”‚       โ”œโ”€โ”€ posix_file.cpp
โ”‚       โ””โ”€โ”€ platform_utils.h
โ”œโ”€โ”€ toolchains/
โ”‚   โ”œโ”€โ”€ linux-arm.cmake
โ”‚   โ”œโ”€โ”€ mingw-w64.cmake
โ”‚   โ””โ”€โ”€ android.cmake
โ””โ”€โ”€ tests/
    โ””โ”€โ”€ crypto_tests.cpp

๐Ÿ’ป ํ•ต์‹ฌ ์ฝ”๋“œ ๊ตฌํ˜„

1. ํ”Œ๋žซํผ ์ถ”์ƒํ™” ์ธํ„ฐํŽ˜์ด์Šค

// platform/file_io.h
#pragma once
#include <string>
#include <vector>
#include <memory>

class IFileIO {
public:
    virtual ~IFileIO() = default;
    virtual bool readFile(const std::string& path, std::vector<uint8_t>& data) = 0;
    virtual bool writeFile(const std::string& path, const std::vector<uint8_t>& data) = 0;
    virtual bool fileExists(const std::string& path) = 0;
    virtual uint64_t getFileSize(const std::string& path) = 0;
};

std::unique_ptr<IFileIO> createFileIO();

2. Windows ๊ตฌํ˜„

// platform/windows_file.cpp
#ifdef _WIN32
#include "file_io.h"
#include <windows.h>
#include <fstream>

class WindowsFileIO : public IFileIO {
public:
    bool readFile(const std::string& path, std::vector<uint8_t>& data) override {
        std::ifstream file(path, std::ios::binary | std::ios::ate);
        if(!file) return false;
        
        auto size = file.tellg();
        data.resize(size);
        file.seekg(0);
        file.read(reinterpret_cast<char*>(data.data()), size);
        return file.good();
    }
    
    bool writeFile(const std::string& path, const std::vector<uint8_t>& data) override {
        std::ofstream file(path, std::ios::binary);
        if(!file) return false;
        
        file.write(reinterpret_cast<const char*>(data.data()), data.size());
        return file.good();
    }
    
    bool fileExists(const std::string& path) override {
        DWORD attr = GetFileAttributesA(path.c_str());
        return (attr != INVALID_FILE_ATTRIBUTES);
    }
    
    uint64_t getFileSize(const std::string& path) override {
        WIN32_FILE_ATTRIBUTE_DATA fileInfo;
        if(!GetFileAttributesExA(path.c_str(), GetFileExInfoStandard, &fileInfo))
            return 0;
        
        LARGE_INTEGER size;
        size.HighPart = fileInfo.nFileSizeHigh;
        size.LowPart = fileInfo.nFileSizeLow;
        return size.QuadPart;
    }
};

std::unique_ptr<IFileIO> createFileIO() {
    return std::make_unique<WindowsFileIO>();
}
#endif

3. POSIX (Linux/macOS) ๊ตฌํ˜„

// platform/posix_file.cpp
#if defined(__linux__) || defined(__APPLE__)
#include "file_io.h"
#include <sys/stat.h>
#include <fstream>

class PosixFileIO : public IFileIO {
public:
    bool readFile(const std::string& path, std::vector<uint8_t>& data) override {
        std::ifstream file(path, std::ios::binary | std::ios::ate);
        if(!file) return false;
        
        auto size = file.tellg();
        data.resize(size);
        file.seekg(0);
        file.read(reinterpret_cast<char*>(data.data()), size);
        return file.good();
    }
    
    bool writeFile(const std::string& path, const std::vector<uint8_t>& data) override {
        std::ofstream file(path, std::ios::binary);
        if(!file) return false;
        
        file.write(reinterpret_cast<const char*>(data.data()), data.size());
        return file.good();
    }
    
    bool fileExists(const std::string& path) override {
        struct stat buffer;
        return (stat(path.c_str(), &buffer) == 0);
    }
    
    uint64_t getFileSize(const std::string& path) override {
        struct stat st;
        if(stat(path.c_str(), &st) != 0)
            return 0;
        return st.st_size;
    }
};

std::unique_ptr<IFileIO> createFileIO() {
    return std::make_unique<PosixFileIO>();
}
#endif

4. ๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

// main.cpp
#include <iostream>
#include <string>
#include "platform/file_io.h"
#include "crypto/aes.h"

int main(int argc, char* argv[]) {
    if(argc < 4) {
        std::cout << "Usage: filecryptor [encrypt|decrypt] input output\n";
        return 1;
    }
    
    std::string mode = argv[1];
    std::string inputPath = argv[2];
    std::string outputPath = argv[3];
    
    auto fileIO = createFileIO();
    
    // ํŒŒ์ผ ์ฝ๊ธฐ
    std::vector<uint8_t> data;
    if(!fileIO->readFile(inputPath, data)) {
        std::cerr << "Failed to read file: " << inputPath << "\n";
        return 1;
    }
    
    std::cout << "Read " << data.size() << " bytes from " << inputPath << "\n";
    
    // ์•”ํ˜ธํ™”/๋ณตํ˜ธํ™”
    std::vector<uint8_t> result;
    if(mode == "encrypt") {
        result = AES::encrypt(data, "my-secret-key");
        std::cout << "Encrypted successfully\n";
    } else if(mode == "decrypt") {
        result = AES::decrypt(data, "my-secret-key");
        std::cout << "Decrypted successfully\n";
    } else {
        std::cerr << "Invalid mode: " << mode << "\n";
        return 1;
    }
    
    // ํŒŒ์ผ ์“ฐ๊ธฐ
    if(!fileIO->writeFile(outputPath, result)) {
        std::cerr << "Failed to write file: " << outputPath << "\n";
        return 1;
    }
    
    std::cout << "Wrote " << result.size() << " bytes to " << outputPath << "\n";
    return 0;
}

5. CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(FileCryptor VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# ์†Œ์Šค ํŒŒ์ผ
set(COMMON_SOURCES
    src/main.cpp
    src/crypto/aes.cpp
)

# ํ”Œ๋žซํผ๋ณ„ ์†Œ์Šค
if(WIN32)
    list(APPEND PLATFORM_SOURCES src/platform/windows_file.cpp)
elseif(UNIX)
    list(APPEND PLATFORM_SOURCES src/platform/posix_file.cpp)
endif()

add_executable(filecryptor ${COMMON_SOURCES} ${PLATFORM_SOURCES})

target_include_directories(filecryptor PRIVATE src)

# ํ”Œ๋žซํผ๋ณ„ ๋งํฌ
if(WIN32)
    # Windows ํŠน๋ณ„ํ•œ ๋งํฌ ์—†์Œ
elseif(APPLE)
    # macOS ํ”„๋ ˆ์ž„์›Œํฌ
    target_link_libraries(filecryptor "-framework CoreFoundation")
elseif(UNIX)
    # Linux pthread
    target_link_libraries(filecryptor pthread)
endif()

# ์„ค์น˜ ๊ทœ์น™
install(TARGETS filecryptor DESTINATION bin)

๐Ÿš€ ๋นŒ๋“œ ๋ฐ ํ…Œ์ŠคํŠธ

# Linux ๋นŒ๋“œ
mkdir build && cd build
cmake ..
make
./filecryptor encrypt test.txt test.enc
./filecryptor decrypt test.enc test_decrypted.txt

# Windows ํฌ๋กœ์Šค ์ปดํŒŒ์ผ (Linux์—์„œ)
mkdir build-windows && cd build-windows
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/mingw-w64.cmake ..
make

# ARM Linux ํฌ๋กœ์Šค ์ปดํŒŒ์ผ
mkdir build-arm && cd build-arm
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/linux-arm.cmake ..
make

๐ŸŒ ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ

์ตœ๊ทผ์—๋Š” Docker๋ฅผ ํ™œ์šฉํ•œ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์ด ์ •๋ง ์ธ๊ธฐ์•ผ! ํ™˜๊ฒฝ ์„ค์ •์ด ๊ฐ„ํŽธํ•˜๊ณ , ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋นŒ๋“œ๋ฅผ ๋ณด์žฅํ•˜๊ฑฐ๋“ . ๐Ÿณ

๐Ÿณ Docker๋ฅผ ํ™œ์šฉํ•œ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๋นŒ๋“œ

1. ๋ฉ€ํ‹ฐ ์Šคํ…Œ์ด์ง€ Dockerfile

# Dockerfile.multiplatform
FROM ubuntu:22.04 AS base
RUN apt-get update && apt-get install -y \
    cmake \
    ninja-build \
    git \
    && rm -rf /var/lib/apt/lists/*

# Linux x86_64 ๋นŒ๋“œ
FROM base AS build-linux-x64
RUN apt-get update && apt-get install -y g++
WORKDIR /app
COPY . .
RUN cmake -B build -G Ninja && cmake --build build
RUN cp build/filecryptor /output/filecryptor-linux-x64

# Linux ARM ํฌ๋กœ์Šค ์ปดํŒŒ์ผ
FROM base AS build-linux-arm
RUN apt-get update && apt-get install -y \
    gcc-arm-linux-gnueabihf \
    g++-arm-linux-gnueabihf
WORKDIR /app
COPY . .
COPY toolchains/linux-arm.cmake .
RUN cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=linux-arm.cmake \
    && cmake --build build
RUN cp build/filecryptor /output/filecryptor-linux-arm

# Windows ํฌ๋กœ์Šค ์ปดํŒŒ์ผ
FROM base AS build-windows
RUN apt-get update && apt-get install -y mingw-w64
WORKDIR /app
COPY . .
COPY toolchains/mingw-w64.cmake .
RUN cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=mingw-w64.cmake \
    && cmake --build build
RUN cp build/filecryptor.exe /output/filecryptor-windows.exe

# ์ตœ์ข… ์ด๋ฏธ์ง€ (๋ชจ๋“  ๋นŒ๋“œ ๊ฒฐ๊ณผ ์ˆ˜์ง‘)
FROM scratch AS export
COPY --from=build-linux-x64 /output/* /
COPY --from=build-linux-arm /output/* /
COPY --from=build-windows /output/* /

2. Docker Buildx๋กœ ๋ฉ€ํ‹ฐ ์•„ํ‚คํ…์ฒ˜ ๋นŒ๋“œ

# buildx ์„ค์ •
docker buildx create --name multiplatform --use
docker buildx inspect --bootstrap

# ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๋นŒ๋“œ ๋ฐ ์ถ”์ถœ
docker buildx build \
    --platform linux/amd64,linux/arm64,linux/arm/v7 \
    --target export \
    --output type=local,dest=./dist \
    -f Dockerfile.multiplatform .

# ๊ฒฐ๊ณผ ํ™•์ธ
ls -lh dist/
# filecryptor-linux-x64
# filecryptor-linux-arm
# filecryptor-windows.exe

3. Docker Compose๋กœ ๋นŒ๋“œ ์ž๋™ํ™”

# docker-compose.yml
version: '3.8'

services:
  build-linux:
    image: gcc:12
    volumes:
      - .:/workspace
    working_dir: /workspace
    command: >
      bash -c "
        mkdir -p build-linux &&
        cd build-linux &&
        cmake .. &&
        make -j$(nproc)
      "
  
  build-windows:
    image: ubuntu:22.04
    volumes:
      - .:/workspace
    working_dir: /workspace
    command: >
      bash -c "
        apt-get update &&
        apt-get install -y cmake mingw-w64 &&
        mkdir -p build-windows &&
        cd build-windows &&
        cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/mingw-w64.cmake .. &&
        make -j$(nproc)
      "
  
  build-arm:
    image: ubuntu:22.04
    volumes:
      - .:/workspace
    working_dir: /workspace
    command: >
      bash -c "
        apt-get update &&
        apt-get install -y cmake gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf &&
        mkdir -p build-arm &&
        cd build-arm &&
        cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/linux-arm.cmake .. &&
        make -j$(nproc)
      "

# ์‹คํ–‰
# docker-compose up

๐Ÿ’ก ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜ ๋นŒ๋“œ์˜ ์žฅ์ 

โœ… ํ™˜๊ฒฝ ์ผ๊ด€์„ฑ: ๋ชจ๋“  ๊ฐœ๋ฐœ์ž๊ฐ€ ๋™์ผํ•œ ๋นŒ๋“œ ํ™˜๊ฒฝ ์‚ฌ์šฉ
โœ… ์˜์กด์„ฑ ๊ฒฉ๋ฆฌ: ํ˜ธ์ŠคํŠธ ์‹œ์Šคํ…œ ์˜ค์—ผ ์—†์Œ
โœ… ์žฌํ˜„ ๊ฐ€๋Šฅ์„ฑ: ์–ธ์ œ๋“  ๋™์ผํ•œ ๊ฒฐ๊ณผ ๋ณด์žฅ
โœ… CI/CD ํ†ตํ•ฉ: ์ž๋™ํ™” ํŒŒ์ดํ”„๋ผ์ธ์— ์‰ฝ๊ฒŒ ํ†ตํ•ฉ
โœ… ๋ฒ„์ „ ๊ด€๋ฆฌ: Dockerfile๋กœ ๋นŒ๋“œ ํ™˜๊ฒฝ ๋ฒ„์ „ ๊ด€๋ฆฌ

๐ŸŽ“ ๊ณ ๊ธ‰ ์ฃผ์ œ: ๋นŒ๋“œ ์‹œ์Šคํ…œ ๋น„๊ต

CMake ์™ธ์—๋„ ๋‹ค์–‘ํ•œ ๋นŒ๋“œ ์‹œ์Šคํ…œ์ด ์žˆ์–ด. ๊ฐ๊ฐ์˜ ์žฅ๋‹จ์ ์„ ์•Œ์•„๋‘๋ฉด ํ”„๋กœ์ ํŠธ์— ๋งž๋Š” ์„ ํƒ์„ ํ•  ์ˆ˜ ์žˆ์ง€! ๐Ÿ”

๋นŒ๋“œ ์‹œ์Šคํ…œ ์žฅ์  ๋‹จ์  ์ ํ•ฉํ•œ ๊ฒฝ์šฐ
CMake ํฌ๋กœ์Šค ํ”Œ๋žซํผ, ๋„๋ฆฌ ์‚ฌ์šฉ๋จ, IDE ํ†ตํ•ฉ ์šฐ์ˆ˜ ๋ฌธ๋ฒ•์ด ๋‹ค์†Œ ๋ณต์žก, ํ•™์Šต ๊ณก์„  ๋Œ€๋ถ€๋ถ„์˜ C++ ํ”„๋กœ์ ํŠธ
Meson ๋น ๋ฅธ ๋นŒ๋“œ ์†๋„, ๊ฐ„๊ฒฐํ•œ ๋ฌธ๋ฒ• ์ƒ๋Œ€์ ์œผ๋กœ ์ ์€ ์‚ฌ์šฉ์ž ๊ธฐ๋ฐ˜ ์ƒˆ ํ”„๋กœ์ ํŠธ, ๋น ๋ฅธ ๋นŒ๋“œ ํ•„์š”
Bazel ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ, ์ฆ๋ถ„ ๋นŒ๋“œ ์ตœ์ ํ™” ๋ณต์žกํ•œ ์„ค์ •, ๊ฐ€ํŒŒ๋ฅธ ํ•™์Šต ๊ณก์„  Google ์Šคํƒ€์ผ ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ
Premake Lua ๊ธฐ๋ฐ˜, ๊ฐ„๋‹จํ•œ ์Šคํฌ๋ฆฝํŒ… ๊ธฐ๋Šฅ์ด ์ œํ•œ์  ๊ฒŒ์ž„ ๊ฐœ๋ฐœ, ์ค‘์†Œ ๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ
xmake ํ˜„๋Œ€์ , Lua ๊ธฐ๋ฐ˜, ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ ๋‚ด์žฅ ๋น„๊ต์  ์ƒˆ๋กœ์šด ๋„๊ตฌ ์ค‘๊ตญ ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ, ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ

๐Ÿ”น Meson ์˜ˆ์ œ

# meson.build
project('filecryptor', 'cpp',
  version : '1.0.0',
  default_options : ['cpp_std=c++17'])

sources = [
  'src/main.cpp',
  'src/crypto/aes.cpp',
]

# ํ”Œ๋žซํผ๋ณ„ ์†Œ์Šค ์ถ”๊ฐ€
if host_machine.system() == 'windows'
  sources += 'src/platform/windows_file.cpp'
elif host_machine.system() in ['linux', 'darwin']
  sources += 'src/platform/posix_file.cpp'
endif

executable('filecryptor',
  sources,
  install : true)

# ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ํŒŒ์ผ (cross-arm.txt)
[binaries]
c = 'arm-linux-gnueabihf-gcc'
cpp = 'arm-linux-gnueabihf-g++'
ar = 'arm-linux-gnueabihf-ar'
strip = 'arm-linux-gnueabihf-strip'

[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'

# ๋นŒ๋“œ
# meson setup build --cross-file cross-arm.txt
# meson compile -C build

๐Ÿ”น Bazel ์˜ˆ์ œ

# BUILD
cc_binary(
    name = "filecryptor",
    srcs = [
        "src/main.cpp",
        "src/crypto/aes.cpp",
    ] + select({
        "@platforms//os:windows": ["src/platform/windows_file.cpp"],
        "@platforms//os:linux": ["src/platform/posix_file.cpp"],
        "@platforms//os:macos": ["src/platform/posix_file.cpp"],
    }),
    hdrs = [
        "src/crypto/aes.h",
        "src/platform/file_io.h",
    ],
    copts = ["-std=c++17"],
)

# ํฌ๋กœ์Šค ์ปดํŒŒ์ผ
# bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_arm64 //:filecryptor

๐Ÿšจ ํ”ํ•œ ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

ํฌ๋กœ์Šค ์ปดํŒŒ์ผํ•˜๋‹ค ๋ณด๋ฉด ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฌธ์ œ์— ๋ถ€๋”ชํžˆ๊ฒŒ ๋ผ. ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋“ค๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•ด๋ดค์–ด! ๐Ÿ”ง

โŒ ๋ฌธ์ œ 1: "Cannot find -lstdc++" ์—๋Ÿฌ

์›์ธ: ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ํˆด์ฒด์ธ์— C++ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—†์Œ

ํ•ด๊ฒฐ:

# ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
sudo apt-get install libstdc++-11-dev-armhf-cross

# ๋˜๋Š” ์ •์  ๋งํฌ
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++")

โŒ ๋ฌธ์ œ 2: ์‹คํ–‰ ์‹œ "cannot execute binary file"

์›์ธ: ์ž˜๋ชป๋œ ์•„ํ‚คํ…์ฒ˜๋กœ ์ปดํŒŒ์ผ๋จ

ํ•ด๊ฒฐ:

# ๋ฐ”์ด๋„ˆ๋ฆฌ ์ •๋ณด ํ™•์ธ
file myapp
# ์ถœ๋ ฅ: myapp: ELF 32-bit LSB executable, ARM, ...

# ์˜ฌ๋ฐ”๋ฅธ ํˆด์ฒด์ธ ์‚ฌ์šฉ ํ™•์ธ
which arm-linux-gnueabihf-g++

# CMake ์บ์‹œ ์‚ญ์ œ ํ›„ ์žฌ๋นŒ๋“œ
rm -rf build && mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake ..

โŒ ๋ฌธ์ œ 3: ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „ ๋ถˆ์ผ์น˜

์›์ธ: ํ˜ธ์ŠคํŠธ์™€ ํƒ€๊ฒŸ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „์ด ๋‹ค๋ฆ„

ํ•ด๊ฒฐ:

# ์ •์  ๋งํฌ ์‚ฌ์šฉ
set(BUILD_SHARED_LIBS OFF)

# ๋˜๋Š” ํƒ€๊ฒŸ ์‹œ์Šคํ…œ์˜ sysroot ์‚ฌ์šฉ
set(CMAKE_SYSROOT /path/to/target/sysroot)
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})

# ์˜์กด์„ฑ์„ ํ•จ๊ป˜ ๋ฐฐํฌ
ldd myapp  # ํ•„์š”ํ•œ .so ํŒŒ์ผ ํ™•์ธ
# ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ•จ๊ป˜ ํŒจํ‚ค์ง•

โŒ ๋ฌธ์ œ 4: ์—”๋””์•ˆ(Endianness) ๋ฌธ์ œ

์›์ธ: ๋น… ์—”๋””์•ˆ๊ณผ ๋ฆฌํ‹€ ์—”๋””์•ˆ ์‹œ์Šคํ…œ ๊ฐ„ ๋ฐ์ดํ„ฐ ๊ตํ™˜

ํ•ด๊ฒฐ:

#include <bit>  // C++20

// ์—”๋””์•ˆ ๋ณ€ํ™˜ ํ•จ์ˆ˜
uint32_t swapEndian(uint32_t value) {
    return ((value & 0xFF000000) >> 24) |
           ((value & 0x00FF0000) >> 8) |
           ((value & 0x0000FF00) << 8) |
           ((value & 0x000000FF) << 24);
}

// ๋„คํŠธ์›Œํฌ ๋ฐ”์ดํŠธ ์ˆœ์„œ ์‚ฌ์šฉ (ํ•ญ์ƒ ๋น… ์—”๋””์•ˆ)
#include <arpa/inet.h>  // POSIX
uint32_t networkValue = htonl(hostValue);  // host to network
uint32_t hostValue = ntohl(networkValue);  // network to host

// C++20 ๋ฐฉ์‹
if constexpr (std::endian::native == std::endian::big) {
    // ๋น… ์—”๋””์•ˆ ์ฒ˜๋ฆฌ
} else {
    // ๋ฆฌํ‹€ ์—”๋””์•ˆ ์ฒ˜๋ฆฌ
}

โŒ ๋ฌธ์ œ 5: ํ”Œ๋žซํผ๋ณ„ ๋งคํฌ๋กœ ์ถฉ๋Œ

์›์ธ: Windows์˜ min/max ๋งคํฌ๋กœ ๋“ฑ์ด C++ ์ฝ”๋“œ์™€ ์ถฉ๋Œ

ํ•ด๊ฒฐ:

// Windows.h ํฌํ•จ ์ „์—
#define NOMINMAX  // min/max ๋งคํฌ๋กœ ๋น„ํ™œ์„ฑํ™”
#define WIN32_LEAN_AND_MEAN  // ๋ถˆํ•„์š”ํ•œ ํ—ค๋” ์ œ์™ธ
#include <windows.h>

// ๋˜๋Š” std::min/max ๋ช…์‹œ์  ์‚ฌ์šฉ
int result = (std::min)(a, b);  // ๊ด„ํ˜ธ๋กœ ๋งคํฌ๋กœ ํ™•์žฅ ๋ฐฉ์ง€

// CMake์—์„œ ์ „์—ญ ์ •์˜
if(WIN32)
    add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN)
endif()

๐Ÿ” ๋””๋ฒ„๊น… ํŒ

1. verbose ๋ชจ๋“œ: `make VERBOSE=1` ๋˜๋Š” `cmake --build . --verbose`๋กœ ์ƒ์„ธ ๋กœ๊ทธ ํ™•์ธ
2. ํˆด์ฒด์ธ ๊ฒ€์ฆ: ๊ฐ„๋‹จํ•œ "Hello World" ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๋จผ์ € ํ…Œ์ŠคํŠธ
3. QEMU ํ™œ์šฉ: ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ํ˜ธ์ŠคํŠธ์—์„œ ์‹คํ–‰ํ•ด๋ณด๊ธฐ
4. ์›๊ฒฉ ๋””๋ฒ„๊น…: gdbserver๋ฅผ ํƒ€๊ฒŸ์—์„œ ์‹คํ–‰ํ•˜๊ณ  ํ˜ธ์ŠคํŠธ์—์„œ ์—ฐ๊ฒฐ
5. ๋กœ๊ทธ ์ถ”๊ฐ€: ํ”Œ๋žซํผ๋ณ„ ์ฝ”๋“œ ๊ฒฝ๋กœ์— ๋กœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์‹คํ–‰ ํ๋ฆ„ ํ™•์ธ

๐Ÿ“š ์ถ”๊ฐ€ ํ•™์Šต ๋ฆฌ์†Œ์Šค

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๊ณผ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๊ฐœ๋ฐœ์€ ์ •๋ง ๋„“์€ ๋ถ„์•ผ์•ผ. ๊ณ„์† ๊ณต๋ถ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด๋Ÿฐ ๋ฆฌ์†Œ์Šค๋“ค์„ ์ฐธ๊ณ ํ•ด๋ด! ๐Ÿ“–

๐Ÿ“˜ ๊ณต์‹ ๋ฌธ์„œ

โ€ข CMake Documentation
โ€ข GCC Cross-Compilation
โ€ข LLVM Cross-Compilation Guide
โ€ข Android NDK Documentation
โ€ข Apple Developer Documentation

๐ŸŽ“ ์˜จ๋ผ์ธ ๊ฐ•์ขŒ

โ€ข Udemy: C++ Cross-Platform Development
โ€ข Coursera: Build Systems
โ€ข YouTube: CMake Tutorial Series
โ€ข ์žฌ๋Šฅ๋„ท์˜ C++ ์ „๋ฌธ๊ฐ€ ๋ฉ˜ํ† ๋ง

๐Ÿ“š ์ถ”์ฒœ ๋„์„œ

โ€ข "Professional CMake"
โ€ข "Cross-Platform Development in C++"
โ€ข "Mastering CMake"
โ€ข "Modern CMake for C++"

๐ŸŒ ์ปค๋ฎค๋‹ˆํ‹ฐ

โ€ข Stack Overflow (cmake, cross-compiling ํƒœ๊ทธ)
โ€ข Reddit r/cpp
โ€ข CMake Discourse
โ€ข C++ Slack ์ปค๋ฎค๋‹ˆํ‹ฐ

๐ŸŽฏ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€, ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ง€? ๐Ÿ˜… ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๊ณผ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๋นŒ๋“œ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์— ๋Œ€ํ•ด ์ •๋ง ๋งŽ์€ ๊ฑธ ๋‹ค๋ค˜์–ด!

๐ŸŒŸ ํ•ต์‹ฌ ์š”์•ฝ

โœ… ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์€ ํ•œ ํ”Œ๋žซํผ์—์„œ ๋‹ค๋ฅธ ํ”Œ๋žซํผ์šฉ ์‹คํ–‰ ํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ๊ธฐ์ˆ 
โœ… CMake๋Š” ํ˜„๋Œ€์ ์ธ C++ ํ”„๋กœ์ ํŠธ์˜ ์‚ฌ์‹ค์ƒ ํ‘œ์ค€ ๋นŒ๋“œ ์‹œ์Šคํ…œ
โœ… ํˆด์ฒด์ธ ํŒŒ์ผ๋กœ ํƒ€๊ฒŸ ํ”Œ๋žซํผ ์ •๋ณด๋ฅผ ์ •์˜
โœ… ํ”Œ๋žซํผ ์ถ”์ƒํ™”๋กœ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ๊ทน๋Œ€ํ™”
โœ… ์˜์กด์„ฑ ๊ด€๋ฆฌ๋Š” Conan์ด๋‚˜ vcpkg ํ™œ์šฉ
โœ… CI/CD๋กœ ์ž๋™ํ™”๋œ ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๋นŒ๋“œ ๊ตฌ์ถ•
โœ… Docker๋กœ ์ผ๊ด€๋œ ๋นŒ๋“œ ํ™˜๊ฒฝ ๋ณด์žฅ
โœ… ํ…Œ์ŠคํŠธ๋Š” ๊ฐ ํ”Œ๋žซํผ์—์„œ ์ฒ ์ €ํžˆ!

ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๊ฐœ๋ฐœ์€ ์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด ๋ณด์ด์ง€๋งŒ, ํ•œ ๋ฒˆ ์ œ๋Œ€๋กœ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•ด๋‘๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋ฌด๊ธฐ๊ฐ€ ๋ผ. ๋„ˆ์˜ ์ฝ”๋“œ๊ฐ€ Windows, Linux, macOS, ๋ชจ๋ฐ”์ผ, ์ž„๋ฒ ๋””๋“œ ๊ธฐ๊ธฐ ๋“ฑ ์–ด๋””์„œ๋“  ๋Œ์•„๊ฐ„๋‹ค๋Š” ๊ฑด ์ •๋ง ๋ฉ‹์ง„ ์ผ์ด์ž–์•„? ๐Ÿš€

์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ์ง€์‹์„ ๊ณต์œ ํ•˜๋ฉด์„œ ๊ณ„์† ์„ฑ์žฅํ•˜๋Š” ๊ฒƒ๋„ ์žŠ์ง€ ๋งˆ! ํ˜ผ์ž ๊ณ ๋ฏผํ•˜์ง€ ๋ง๊ณ , ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ํž˜์„ ํ™œ์šฉํ•˜๋Š” ๊ฑฐ์•ผ. ๐Ÿ’ช

์ด์ œ ๋„ˆ๋„ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ๋งˆ์Šคํ„ฐ๊ฐ€ ๋  ์ค€๋น„๊ฐ€ ๋์–ด! ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด๋ฉด์„œ ๊ฒฝํ—˜์„ ์Œ“์•„๊ฐ€๊ธธ ๋ฐ”๋ž„๊ฒŒ. ์ฒ˜์Œ์—๋Š” ์‹ค์ˆ˜๋„ ํ•˜๊ณ  ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„๋„ ์žˆ๊ฒ ์ง€๋งŒ, ๊ทธ๊ฒŒ ๋‹ค ์„ฑ์žฅ์˜ ๊ณผ์ •์ด๋‹ˆ๊นŒ ํฌ๊ธฐํ•˜์ง€ ๋ง๊ณ  ๊ณ„์† ๋„์ „ํ•ด๋ด! ๐ŸŒˆ

Happy Cross-Compiling! ๐ŸŽ‰

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0