J2ObjC에서 생성된 헤더 파일은 세그먼트로 나뉘며 한 번에 하나의 세그먼트만 포함할 수 있습니다. 번역된 Java 유형마다 하나의 세그먼트가 생성되므로 각 내부 클래스에는 자체 세그먼트가 있습니다. 전처리기 매크로는 헤더를 포함할 때 컴파일러에 특정 세그먼트만 읽으라고 지시하는 데 사용됩니다. 세그먼트화된 헤더는 이 문서에 자세히 설명된 J2ObjC 생성 헤더의 포함 순환 문제를 해결합니다.
알아야 할 사항
#import
대신#include
를 사용하여 J2ObjC 생성 헤더를 포함합니다.- 세그먼트화된 헤더와 함께
#import
를 사용하면 문제가 됩니다. 컴파일러가 이미 헤더를 본 경우 헤더 읽기를 건너뛰기 때문입니다. 하지만 헤더가 세그먼트화되어 있으므로 컴파일러에서 처음에 완전히 파싱하지 못했을 수 있습니다.
- 세그먼트화된 헤더와 함께
- 세그먼트화된 헤더는
--no-segmented-headers
플래그를 사용하여 사용 중지할 수 있습니다.
전단 포함 내용
J2ObjC에서 생성된 헤더 파일은 포함과 전방 선언을 사용하여 필요한 유형 정보를 확인해야 합니다. 선언은 최대한 많이 사용되지만 컴파일러에 전체 유형 선언이 필요하므로 확장되거나 구현되는 유형에는 포함이 필요합니다.
J2ObjC 생성 헤더 파일에서 포함 순환을 생성할 수 있습니다. 이러한 순환을 얻으려면 파일 B의 클래스를 확장하는 파일 A의 클래스와 파일 A의 클래스를 확장하는 파일 B의 클래스가 필요합니다. 이는 발생 가능성이 낮은 시나리오이지만 Guava의 코드베이스 (및 기타 위치)에서는 발생합니다.
이 문제를 해결하는 자연스러운 방법은 .java 파일에서 발생하는 각 Java 유형에 대해 별도의 헤더 파일을 내보내는 것입니다. 하지만 J2ObjC는 빌드 도구로 사용되도록 설계되었으며, 우수한 빌드 시스템은 각 입력에 대해 예측 가능한 출력을 사용합니다. 즉, 각 .java 파일은 정확히 하나의 .h 파일과 하나의 .m 파일을 생성해야 합니다.
예
Foo.java:
class Foo extends Bar {}
Bar.java:
class Bar {
static class Baz extends Foo {}
}
Foo.h (세그먼트되지 않음):
#ifndef _Foo_H_
#define _Foo_H_
#include "Bar.h"
#include "J2ObjC_header.h"
@interface Foo : Bar
- (instancetype)init;
@end
#endif // _Foo_H_
Bar.h (세그먼트되지 않음):
#ifndef _Bar_H_
#define _Bar_H_
#include "Foo.h"
#include "J2ObjC_header.h"
@interface Bar : NSObject
- (instancetype)init;
@end
@interface Bar_Baz : Foo
- (instancetype)init;
@end
#endif // _Bar_H_
Foo.h에는 Bar.h가 포함되어 있고 Bar.h에는 Foo.h가 포함되어 있습니다. 따라서 다음 헤더가 컴파일되지 않습니다.
../dist/j2objcc -c Foo.m
In file included from Foo.m:6: In file included from ./Bar.h:9: ./Foo.h:12:18: error: cannot find interface declaration for 'Bar', superclass of 'Foo' @interface Foo : Bar ~~~~~~~~~~~~~~ ^
오류 없이 컴파일되는 Foo.h 및 Bar.h의 세그먼트화된 버전:
Foo.h (세그먼트화됨):
#include "J2ObjC_header.h"
#pragma push_macro("Foo_INCLUDE_ALL")
#if Foo_RESTRICT
#define Foo_INCLUDE_ALL 0
#else
#define Foo_INCLUDE_ALL 1
#endif
#undef Foo_RESTRICT
#if !defined (_Foo_) && (Foo_INCLUDE_ALL || Foo_INCLUDE)
#define _Foo_
#define Bar_RESTRICT 1
#define Bar_INCLUDE 1
#include "Bar.h"
@interface Foo : Bar
- (instancetype)init;
@end
#endif
#pragma pop_macro("Foo_INCLUDE_ALL")
Bar.h (세분화됨):
#include "J2ObjC_header.h"
#pragma push_macro("Bar_INCLUDE_ALL")
#if Bar_RESTRICT
#define Bar_INCLUDE_ALL 0
#else
#define Bar_INCLUDE_ALL 1
#endif
#undef Bar_RESTRICT
#if !defined (_Bar_) && (Bar_INCLUDE_ALL || Bar_INCLUDE)
#define _Bar_
@interface Bar : NSObject
- (instancetype)init;
@end
#endif
#if !defined (_Bar_Baz_) && (Bar_INCLUDE_ALL || Bar_Baz_INCLUDE)
#define _Bar_Baz_
#define Foo_RESTRICT 1
#define Foo_INCLUDE 1
#include "Foo.h"
@interface Bar_Baz : Foo
- (instancetype)init;
@end
#endif
#pragma pop_macro("Bar_INCLUDE_ALL")