1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
|
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="parallel-installability" xml:lang="ko">
<info>
<link type="guide" xref="index#maintainer-guidelines"/>
<credit type="author copyright">
<name>Havoc Pennington</name>
<email its:translate="no">hp@pobox.com</email>
<years>2002</years>
<!-- Heavily based off Havoc’s original article about parallel
installability: http://ometer.com/parallel.html.
License CC-BY-SA 3.0 confirmed by e-mail with him. -->
</credit>
<credit type="author copyright">
<name>Philip Withnall</name>
<email its:translate="no">philip.withnall@collabora.co.uk</email>
<years>2015</years>
</credit>
<include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>
<desc>동시 설치 방식으로 나중에 검증할 라이브러리를 작성합니다</desc>
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
<mal:name>조성호</mal:name>
<mal:email>shcho@gnome.org</mal:email>
<mal:years>2016-2018.</mal:years>
</mal:credit>
</info>
<title>동시 설치 가능성</title>
<synopsis>
<title>요약</title>
<p>두 패키지를 동시에 설치할 수 있다면, 일반적인 파일 이름이 붙어있지 않으며 패키지를 개발한 사람은 원하는 버전에 따라 컴파일합니다. 이 방식은 헤더 파일, 라이브러리 이진 파일에 적용하는 방식대로 데몬, 유틸리티 프로그램, 설정 파일에 적용합니다.</p>
<list>
<item><p>모든 라이브러리 버전을 동시에 설치할 수 있는지 확인하십시오(<link xref="#justification"/>).</p></item>
<item><p>라이브러리로 설치한 모든 파일에 버전을 부여하십시오(<link xref="#solution"/>).</p></item>
<item><p>so 이름 또는 libtool 버전 번호와는 별개로 패키지 버전 번호를 관리하십시오. 어떤 패키지 버전 번호 부분이 API와 바뀌는지 분명히 하십시오(<link xref="#version-numbers"/>).</p></item>
<item><p><file><var>$(includedir)</var>/lib<var>library</var>-<var>version</var>/<var>library</var>/</file>에 C 헤더 파일을 설치하십시오(<link xref="#header-files"/>).</p></item>
<item><p><file><var>$(libdir)</var>/lib<var>library</var>-<var>version</var>.so.<var>soname</var></file>에 라이브러리 파일을 설치하십시오(<link xref="#libraries"/>).</p></item>
<item><p><file><var>$(libdir)</var>/pkgconfig/<var>library</var>-<var>version</var>.pc</file>에 pkg-config 파일을 설치하십시오(<link xref="#pkg-config"/>).</p></item>
<item><p>설정 파일을 전후 호환성에 맞추든지 <file><var>$(sysconfdir)</var>/<var>library</var>-<var>version</var>/</file>에 설치하십시오(<link xref="#configuration-files"/>).</p></item>
<item><p><code>GETTEXT_PACKAGE</code> 변수 값을 <code><var>library</var>-<var>version</var></code>에 설정하십시오(<link xref="#gettext"/>).</p></item>
<item><p>모든 D-Bus 인터페이스 이름, 서비스 이름, 객체 경로에 버전 번호를 넣으십시오. 이를 테면 <code>org.domain.<var>Library</var><var>Version</var>.<var>Interface</var></code>, <code>org.domain.<var>Library</var><var>Version</var></code>, <code>/org/domain/<var>Library</var><var>Version</var>/</code> 과 같이 넣으십시오(<link xref="#dbus"/>).</p></item>
<item><p>데몬 바이너리를 <file><var>$(libexecdir)</var>/<var>library</var>-daemon-<var>version</var></file>에 설치하십시오(<link xref="#programs"/>).</p></item>
<item><p>유틸리티 바이너리를 <file><var>$(bindir)</var>/<var>library</var>-utility-<var>version</var></file> and install symbolic links to <file><var>$(bindir)</var>/<var>library</var>-utility</file>에 설치하십시오(<link xref="#programs"/>).</p></item>
</list>
</synopsis>
<section id="justification">
<title>명분</title>
<p>모든 공개 라이브러리는 라이브러리의 생명 주기 이후 API 구조 변경이 쉽게 함께 설치할 수 있도록 설계해야합니다. 라이브러리를 여러 프로젝트에서 사용하는 상황에서 API 구조를 깨야 한다면, 모든 프로젝트를 동시에 설치한 새 API에 맞춰 이식해야 하며, 이렇게 하지 않으면 일부 프로젝트는 의존 관계상 라이브러리 버전이 맞지 않는 문제로 더이상 라이브러리와 설치할 수 없습니다.</p>
<p>이 상태가 바로 관리할 수 없는 상태이며, 대부분의 API가 이식의 동기가 될 눈에 띄는 새 기능을 넣지 않기에, 모든 프로젝트에 새 API에 맞춰 동시에 이식을 요청하기 어렵고, 이식의 의욕을 꺾어버립니다.</p>
<p>API의 이전 버전과 새 버전을 동시에 설치하고 컴파일 할 수 있게끔 모든 라이브러리를 동시에 설치할 수 있게 했는지 확인하면 이 문제가 처리됩니다. 동시에 설치할 수 있게 빌드하면, 굳이 근본 부분을 건드리지 않고도 프로젝트의 시작단계를 쉽게 처리할 수 있습니다.</p>
<p>이 해결 방식은 또한 라이브러리의 어떤 버전과 그 다음 버전을 설치하는 문제에서 여러 프로그램을 이식하는 ‘닭이 먼저냐 달걀이 먼저냐’의 문제를 해결하며, 라이브러리 관리 집단이 원한다면 개발 주기를 더 빠르게 진행할 수 있으며 개발 과정상 새 기능을 넣을 수 있도록 API 구조를 훨씬 쉽게 바꿀 수 있습니다.</p>
<p>이와 동일한 라이브러리 대상 해결책은 API 구조를 그냥 안바꾸는 방법입니다. 이 접근 방식은 <code>libc</code>에서 왔습니다.</p>
</section>
<section id="solution">
<title>해결책</title>
<p>문제 해결책은 근본적으로 라이브러리의 이름을 바꾸는 방식이며, 대부분의 경우 모든 파일을 설치하는 경로의 버전 번호를 넣는 방식입니다. 이는 라이브러리의 여러 버전을 동시에 설치할 수 있다는 의미입니다.</p>
<p>예를 들어 <code>Foo</code> 라이브러리에서 기존에 설치한 파일이 다음과 같다고 하겠습니다:</p>
<list>
<item><p><file>/usr/include/foo.h</file></p></item>
<item><p><file>/usr/include/foo-utils.h</file></p></item>
<item><p><file>/usr/lib/libfoo.so</file></p></item>
<item><p><file>/usr/lib/pkgconfig/foo.pc</file></p></item>
<item><p><file>/usr/share/doc/foo/foo-manual.txt</file></p></item>
<item><p><file>/usr/bin/foo-utility</file></p></item>
</list>
<p>이 파일을 설치하려면 위 대신 <code>Foo</code> 버전 4로 수정해야합니다:</p>
<list>
<item><p><file>/usr/include/foo-4/foo/foo.h</file></p></item>
<item><p><file>/usr/include/foo-4/foo/utils.h</file></p></item>
<item><p><file>/usr/lib/libfoo-4.so</file></p></item>
<item><p><file>/usr/lib/pkgconfig/foo-4.pc</file></p></item>
<item><p><file>/usr/share/doc/foo-4/foo-manual.txt</file></p></item>
<item><p><file>/usr/bin/foo-utility-4</file></p></item>
</list>
<p>수정하고 나면 버전 5로 동시에 설치할 수 있습니다:</p>
<list>
<item><p><file>/usr/include/foo-5/foo/foo.h</file></p></item>
<item><p><file>/usr/include/foo-5/foo/utils.h</file></p></item>
<item><p><file>/usr/lib/libfoo-5.so</file></p></item>
<item><p><file>/usr/lib/pkgconfig/foo-5.pc</file></p></item>
<item><p><file>/usr/share/doc/foo-5/foo-manual.txt</file></p></item>
<item><p><file>/usr/bin/foo-utility-5</file></p></item>
</list>
<p><link href="http://www.freedesktop.org/wiki/Software/pkg-config/"> <cmd>pkg-config</cmd></link>에서 쉽게 기능을 빌려 쓸 수 있습니다. <file>foo-4.pc</file> 파일은 include 경로에 <file>/usr/include/foo-4</file> 경로를 추가하고 링크할 라이브러리 목록에 <file>libfoo-4.so</file> 파일을 추가합니다. <file>foo-5.pc</file> 파일은 <file>/usr/include/foo-5</file> 경로와 <file>libfoo-5.so</file> 파일을 추가합니다.</p>
</section>
<section id="version-numbers">
<title>버전 번호</title>
<p>파일 이름에 붙은 버전 번호는 <em>ABI/API</em> 버전입니다. 패키지의 전체 버전 번호는 아닙니다. API 유지 상태가 깨졌는지 여부를 나타내는 부분일 뿐입니다. 프로젝트 버전 부여시 <code><var>주</var>.<var>부</var>.<var>마이크로</var></code> 표준 버전 부여 형식을 사용한다면 API 버전은 보통 주 버전 번호입니다.</p>
<p>부 버전 출시판(보통 API를 추가하지만 바꾸거나 제거하지 <em>않음</em>)과 마이크로 버전 출시판(보통 버그 수정)은 <link xref="api-stability">API 이전 호환성</link>에 영향을 주지 않으므로 모든 파일을 옮길 필요가 없습니다.</p>
<p>다음 부분의 예제는 다음 코드를 활용하여 <file>configure.ac</file> 파일에서 API 버전과 so 이름을 내보낸다고 가정합니다:</p>
<listing>
<title>autoconf의 API 버전 부여</title>
<desc><file>configure.ac</file> 파일에 API 버전 및 so 이름을 내보낼 코드를 작성하십시오</desc>
<code># Before making a release, the <var>LIBRARY</var>_LT_VERSION string should be modified.
# The string is of the form c:r:a. Follow these instructions sequentially:
#
# 1. If the library source code has changed at all since the last update,
# then increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
# 2. If any interfaces have been added, removed, or changed since the last update,
# increment current, and set revision to 0.
# 3. If any interfaces have been added since the last public release,
# then increment age.
# 4. If any interfaces have been removed or changed since the last public release,
# then set age to 0.
AC_SUBST([<var>LIBRARY</var>_LT_VERSION],[1:0:0])
AC_SUBST([<var>LIBRARY</var>_API_VERSION],[4])</code>
</listing>
</section>
<section id="header-files">
<title>C 헤더 파일</title>
<p>헤더 파일은 C 컴파일러의 <cmd>-I</cmd> 플래그가 요구하는 버전이 붙은 하위 디렉터리에 항상 설치해야합니다. 예를 들어, <file>foo.h</file> 헤더 파일이 있다면 프로그램에서는 다음과 같이 씁니다:</p>
<code mime="text/x-csrc">#include <foo/foo.h></code>
<p>그 다음 이 파일을 설치하겠습니다:</p>
<list>
<item><p><file>/usr/include/foo-4/foo/foo.h</file></p></item>
<item><p><file>/usr/include/foo-5/foo/foo.h</file></p></item>
</list>
<p>프로그램에서는 <cmd>-I/usr/include/foo-4</cmd> 또는 <cmd>-I/usr/include/foo-5</cmd> 플래그를 C 컴파일러에 보내야합니다. 다시 말하지만, <cmd>pkg-config</cmd>를 활용하면 됩니다.</p>
<p><file>foo/</file> 추가 하위 디렉터리를 살펴보십시오. 다른 라이브러리의 파일 이름이 겹치는 일을 피하도록 <code mime="text/x-csrc">#include</code> 절에 이름 영역을 부여합니다. 예를 들자면, 서로 다른 두 라이브러리에서 <file>utils.h</file> 헤더 파일을 설치한다면 <code mime="text/x-csrc">#include <utils.h></code> 헤더를 사용할 때 무얼 넣을까요?</p>
<p>어떤 하위 디렉터리 외에 있는 헤더 파일 중 하나를 두어야 할 지 망설임이 옵니다:</p>
<list>
<item><p><file>/usr/include/foo.h</file></p></item>
<item><p><file>/usr/include/foo-5/foo.h</file></p></item>
</list>
<p>문제는 사용자가 언제나 부주의하게 잘못된 헤더를 참조하는데, 컴파일 명령행에 <cmd>-I/usr/include</cmd>를 넣는걸 규칙인 것 처럼 생각하기 때문입니다. 만약 이렇게 해야 한다면, 최소한 라이브러리를 초기화할 때 잘못된 헤더 파일을 사용하여 프로그램을 감지하는 라이브러리가 있는지 검사하는 부분을 추가하십시오.</p>
<p>버전을 부여한 헤더 파일은 다음 코드로 automake에서 설치할 수 있습니다:</p>
<listing>
<title>automake의 헤더 파일 처리</title>
<desc><file>Makefile.am</file> 파일에 버전을 부여한 헤더 파일을 설치할 코드를 작성하십시오</desc>
<code><var>library</var>includedir = $(includedir)/lib<var>library</var>-@<var>LIBRARY</var>_API_VERSION@/<var>library</var>
<var>library</var>_headers = \
lib<var>library</var>/example1.h \
lib<var>library</var>/example2.h \
$(NULL)
# The following headers are private, and shouldn't be installed:
private_headers = \
lib<var>library</var>/example-private.h \
$(NULL)
# The main header simply #includes all other public headers:
main_header = lib<var>library</var>/<var>library</var>.h
public_headers = \
$(main_header) \
$(<var>library</var>_headers) \
$(NULL)
<var>library</var>include_HEADERS = $(public_headers)</code>
</listing>
<p>버전을 올바르게 부여하는 것처럼, 설치한 헤더에 있는 모든 API의 <link xref="namespacing">공간 이름을 올바르게 부여</link>해야합니다.</p>
</section>
<section id="libraries">
<title>라이브러리</title>
<p>라이브러리 객체 파일은 다음과 같이 버전을 붙인 이름을 달고 있어야합니다:</p>
<list>
<item><p><file>/usr/lib/libfoo-4.so</file></p></item>
<item><p><file>/usr/lib/libfoo-5.so</file></p></item>
</list>
<p>이 과정으로 컴파일을 진행하는 동안 원하는 프로그램이 제대로 나오며, 일반적으로 버전 4 및 버전 5에 파일이 없는지 확인합니다.</p>
<p>버전을 매긴 라이브러리는 다음 코드로 automake에서 빌드하고 설치할 수 있습니다:</p>
<listing>
<title>automake의 라이브러리 처리</title>
<desc><file>Makefile.am</file>에 버전을 매긴 파일을 빌드하고 설치하는 코드를 작성하십시오</desc>
<code>lib_LTLIBRARIES = lib<var>library</var>/lib<var>library</var>-@<var>LIBRARY</var>_API_VERSION@.la
lib<var>library</var>_lib<var>library</var>_@<var>LIBRARY</var>_API_VERSION@_la_SOURCES = \
$(private_headers) \
$(<var>library</var>_sources) \
$(NULL)
lib<var>library</var>_lib<var>library</var>_@<var>LIBRARY</var>_API_VERSION@_la_CPPFLAGS = …
lib<var>library</var>_lib<var>library</var>_@<var>LIBRARY</var>_API_VERSION@_la_CFLAGS = …
lib<var>library</var>_lib<var>library</var>_@<var>LIBRARY</var>_API_VERSION@_la_LIBADD = …
lib<var>library</var>_lib<var>library</var>_@<var>LIBRARY</var>_API_VERSION@_la_LDFLAGS = \
-version-info $(<var>LIBRARY</var>_LT_VERSION) \
$(AM_LDFLAGS) \
$(NULL)</code>
</listing>
<section id="library-sonames">
<title>라이브러리 so 이름</title>
<p>라이브러리 so 이름(libtool 버전 번호로도 알려짐)은 앞서 컴파일한 프로그램을 연결하는 실행시 문제만을 해결합니다. 이전 버전에서 필요한 프로그램을 컴파일하는 문제를 바로잡을 수 없으며, 다른 라이브러리의 문제는 바로 잡지 않습니다.</p>
<p>이 때문에, so 이름을 활용하지만, <em>추가로</em> 라이브러리의 이름에 버전을 붙입니다. 각각의 문제를 두가지 해결책으로 바로 잡습니다.</p>
</section>
</section>
<section id="pkg-config">
<title>pkg-config 파일</title>
<p>다음과 같이 pkg-config 파일에 버전을 매긴 이름을 넣어야합니다:</p>
<list>
<item><p><file>/usr/lib/pkgconfig/foo-4.pc</file></p></item>
<item><p><file>/usr/lib/pkgconfig/foo-5.pc</file></p></item>
</list>
<p>각각의 pkg-config 파일에 라이브러리 이름과 수반 경로의 버전 정보가 있기 때문에 라이브러리에 의존하는 어떤 프로젝트든지간에 <file>foo-4</file> 파일에서 <file>foo-5</file> 파일로 pkg-config check를 바꾸(고 API 이식 필요 과정을 진행하)는 방법만으로 버전을 바꿀 수 있어야합니다.</p>
<p>버전을 부여한 pkg-config 파일은 다음 코드로 autoconf 및 automake에서 설치할 수 있어야합니다:</p>
<listing>
<title>autoconf와 automake의 pkg-config 파일 처리</title>
<desc><file>configure.ac</file>파일과 <file>Makefile.am</file> 파일에 버전을 부여한 pkg-config 파일을 설치하는 코드를 작성하십시오</desc>
<code>AC_CONFIG_FILES([
lib<var>library</var>/<var>library</var>-$<var>LIBRARY</var>_API_VERSION.pc:lib<var>library</var>/<var>library</var>.pc.in
],[],
[<var>LIBRARY</var>_API_VERSION='$<var>LIBRARY</var>_API_VERSION'])</code>
<code># Note that the template file is called <var>library</var>.pc.in, but generates a
# versioned .pc file using some magic in AC_CONFIG_FILES.
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = lib<var>library</var>/<var>library</var>-$(<var>LIBRARY</var>_API_VERSION).pc
DISTCLEANFILES += $(pkgconfig_DATA)
EXTRA_DIST += lib<var>library</var>/<var>library</var>.pc.in</code>
</listing>
</section>
<section id="configuration-files">
<title>설정 파일</title>
<p>사용자 관점에서, <link xref="api-stability">전후 호환성</link>(정확히 동일한 설정 파일 및 문맥을 각 라이브러리 버전에서 이해)에 따라 설정 파일 형식을 유지하는게 좋습니다. 그 다음 동일한 설정 파일을 모든 라이브러리 버전에서 활용할 수 있으며, 설정 파일 자체를 버전 관리할 필요가 없습니다.</p>
<p>이렇게 할 수 있다면, 간단하게 설정 파일의 이름을 바꿔야 하며, 사용자는 각 라이브러리 버전 별로 따로 설정해야합니다.</p>
</section>
<section id="gettext">
<title>gettext 번역</title>
<p>autoconf와 automake의 번역 기반으로 gettext를 사용한다면 보통 <file>/usr/share/locale/<var>lang</var>/LC_MESSAGES/<var>package</var></file> 경로에 번역 파일을 설치합니다. 여기서 <var>package</var> 변수를 추가해야합니다. 그놈에서는 <file>configure.ac</file>에 이 변수를 넣는 방식을 활용합니다:</p>
<code>GETTEXT_PACKAGE=foo-4
AC_SUBST([GETTEXT_PACKAGE])
AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],["$GETTEXT_PACKAGE"])</code>
<p>그 다음 <code mime="text/x-csrc">bindtextdomain()</code>, <code mime="text/x-csrc">textdomain()</code>, <code mime="text/x-csrc">dgettext()</code>에 패키지 이름을 전달할 목적으로 <code>GETTEXT_PACKAGE</code>를 활용합니다.</p>
</section>
<section id="dbus">
<title>D-Bus 인터페이스</title>
<p>D-Bus 인터페이스는 컴파일 시간이 아닌 실행 시간에 버전 관리를 처리할 때를 제외하고는 C API와 유사한 API의 한 유형입니다. D-Bus 인터페이스 버전 부여는 다른 C API와 별반 차이가 없습니다. 버전 숫자는 인터페이스 이름, 서비스 이름, 객체 경로에 있어야합니다.</p>
<p>이를테면, 다음과 같이 <code>org.example.Foo</code> 서비스에는 <code>Controller</code>와 <code>Client</code>의 <code>A</code> 와 <code>B</code>, D-Bus API 버전 4와 5가 나타나야합니다:</p>
<list>
<title>서비스 이름</title>
<item><p><code>org.example.Foo4</code></p></item>
<item><p><code>org.example.Foo5</code></p></item>
</list>
<list>
<title>인터페이스 이름</title>
<item><p><code>org.example.Foo4.InterfaceA</code></p></item>
<item><p><code>org.example.Foo4.InterfaceB</code></p></item>
<item><p><code>org.example.Foo5.InterfaceA</code></p></item>
<item><p><code>org.example.Foo5.InterfaceB</code></p></item>
</list>
<list>
<title>객체 경로</title>
<item><p><code>/org/example/Foo4/Controller</code></p></item>
<item><p><code>/org/example/Foo4/Client</code></p></item>
<item><p><code>/org/example/Foo5/Controller</code></p></item>
<item><p><code>/org/example/Foo5/Client</code></p></item>
</list>
</section>
<section id="programs">
<title>프로그램, 데몬, 유틸리티</title>
<p>데스크톱 프로그램은 보통 다른 모듈과 의존 관계가 없기 때문에 버전을 매길 필요가 없습니다. 그러나 데몬과 유틸리티 프로그램은 시스템의 다른 부분과 함께 동작하므로 버전을 매겨야 합니다.</p>
<p>다음의 데몬 및 유틸리티 프로그램을:</p>
<list>
<item><p><file>/usr/libexec/foo-daemon</file></p></item>
<item><p><file>/usr/bin/foo-lookup-utility</file></p></item>
</list>
<p>다음과 같이 버전을 부여합니다:</p>
<list>
<item><p><file>/usr/libexec/foo-daemon-4</file></p></item>
<item><p><file>/usr/bin/foo-lookup-utility-4</file></p></item>
</list>
<p>사용자가 편리하게 쓸 수 있게 <file>/usr/bin/foo-lookup-utility</file>를 유틸리티의 추천 버전 사본으로 심볼릭 링크 사본을 설치하고 싶을 수도 있습니다.</p>
</section>
</page>
|