J2ObjC 生成的头文件会分为若干段,一次可以包含一个段。系统会为每个转换后的 Java 类型创建一个段,因此每个内部类都将有自己的段。预处理器宏用于告知编译器在包含标头时仅读取特定片段。分段标头解决了 J2ObjC 生成的标头中的包含循环问题,详见下文。
须知事项
- 请使用
#include
(而非#import
)包含 J2ObjC 生成的头文件。- 将
#import
与分段标头一起使用会带来问题,因为编译器会跳过已看到标头的读取步骤。但是,由于标头已细分,因此编译器在第一次时可能未完全解析该标头。
- 将
- 您可以使用
--no-segmented-headers
标志停用分段标头。
循环包含
J2ObjC 生成的头文件必须使用 include 和前向声明来解析必要的类型信息。尽可能多地使用前向声明,但对于要扩展或实现的类型,必须使用 include,因为编译器需要完整的类型声明。
可以在 J2ObjC 生成的头文件中生成包含循环。为了实现这种循环,我们需要文件 A 中的一个类扩展文件 B 中的一个类,以及文件 B 中的一个类扩展文件 A 中的类。这种情况不太可能发生,但确实发生在 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")