Macro Package Definition and Import
Inspect one language lane at a time so line-level text and code deltas stay readable.
Diff Lane
English
0 modified sections0 code block delta0 anchor delta
Diff Lane
中文
1 modified sections0 code block delta0 anchor delta
modified宏包定义和导入text+8 lines, -4 lines
v1.0.5
Section Text
1
仓颉语言中宏的定义需要放在由 `macro package` 声明的包中,被 `macro package` 限定的包仅允许宏定义对外可见,其他声明包内可见。2
3
> **说明:**4
>5
> 重导出的声明也允许对外可见,关于包管理和重导出的相关概念,请参见[包的导入](../package/import.md)章节。6
7
<!-- compile.error -macro4 -->8
<!-- cfg="--compile-macro" -->9
10
11
需要特殊说明的是,在宏包中,允许其他宏包和非宏包的声明被重导出。在非宏包中仅允许非宏包的声明被重导出。12
13
参考如下示例:14
15
- 在宏包 A 中定义宏 `M1`16
17
<!-- compile -macro5 -->18
<!-- cfg="--compile-macro" -->19
20
```cangjie21
macro package A22
import std.ast.*23
24
public macro M1(input: Tokens): Tokens {25
return input26
}27
```28
29
编译命令如下:30
31
```shell32
cjc A.cj --compile-macro33
```34
35
- 在非宏包 B 中定义一个 public 函数 `f1`。注意在非 `macro package` 中无法重导出 `macro package` 的符号36
37
<!-- compile -macro5 -->38
<!-- cfg="--output-type=dylib -o libB.so" -->39
40
```cangjie41
package B42
// public import A.* // Error, it is not allowed to re-export a macro package in a package.43
44
public func f1(input: Int64): Int64 {45
return input46
}47
```48
49
编译命令如下,这里选择使用 `--output-type` 选项将 B 包编译成动态库,关于 cjc 编译选项介绍可以参考 "附录 > cjc 编译选项" 章节。50
51
```shell52
cjc B.cj --output-type=dylib -o libB.so53
```54
55
- 在宏包 C 中定义宏 `M2`,依赖了 A 包和 B 包的内容。可以看到 `macro package` 中可以重导出 `macro package` 和非 `macro package` 的符号56
57
<!-- compile -macro5 -->58
<!-- cfg="--compile-macro -L. -lB" -->59
60
```cangjie61
macro package C62
public import A.* // correct: macro package is allowed to re-export in a macro package.63
public import B.* // correct: non-macro package is also allowed to re-export in a macro package.64
import std.ast.*65
66
public macro M2(input: Tokens): Tokens {67
return @M1(input) + Token(TokenKind.NL) + quote(f1(1))68
}69
```70
71
编译命令如下,注意这里需要显式链接 B 包动态库:72
73
```cangjie74
cjc C.cj --compile-macro -L. -lB75
```76
77
- 在 `main.cj` 中使用 `M2` 宏78
79
<!-- compile -macro5 -->80
<!-- cfg="--compile-macro -L. -lB" -->81
82
```cangjie83
import C.*84
85
main() {86
@M2(let a = 1)87
}88
```89
90
编译命令如下:91
92
```cangjie93
cjc main.cj -o main -L. -lB94
```95
96
`main.cj`中 `M2` 宏展开后的结果如下:97
98
```cangjie99
import C.*100
101
main() {102
let a = 1103
f1(1)104
}105
```106
107
可以看到 `main.cj` 中出现了来自于 B 包的符号 `f1`。宏的编写者可以在 C 包中重导出 B 包里的符号,这样宏的使用者仅需导入宏包,就可以正确地编译宏展开后的代码。如果在 `main.cj` 中仅使用 `import C.M2` 导入宏符号,则会报 `undeclared identifier 'f1'` 的错误信息。Code 1 · cangjie
1
// file define.cj2
macro package define // 编译 define.cjo 携带 macro 属性3
import std.ast.*4
5
public func A() {} // Error, 宏包不允许定义外部可见的非宏定义,此处会报错6
7
public macro M(input: Tokens): Tokens { // macro M 外部可见8
return input9
}v1.1.0
Section Text
1
仓颉语言中宏的定义需要放在由 `macro package` 声明的包中,被 `macro package` 限定的包仅允许宏定义对外可见,其他声明包内可见。2
3
<!-- compile.error -macro4 -->4
<!-- cfg="--compile-macro" -->5
6
7
> **说明:**8
>9
> - 重导出的声明也允许对外可见,关于包管理和重导出的相关概念,请参见[包的导入](../package/import.md)章节。10
> - 在宏包中,允许其他宏包和非宏包的声明被重导出。在非宏包中仅允许非宏包的声明被重导出。11
> - 使用宏时,需要同时导入该宏依赖的包(宏定义时如果重导出了依赖的部分,则可以不导入依赖包),并在使用 cjc 编译时用 -l 连接依赖包。否则,代码编译过程中会报错(找不到相关依赖)。12
13
在宏包中重导出宏包和非宏包,示例如下:14
15
- 在宏包 A 中定义宏 `M1`16
17
<!-- compile -macro5 -->18
<!-- cfg="--compile-macro" -->19
20
```cangjie21
macro package A22
import std.ast.*23
24
public macro M1(input: Tokens): Tokens {25
return input26
}27
```28
29
编译命令如下:30
31
```shell32
cjc A.cj --compile-macro33
```34
35
- 在非宏包 B 中定义一个 public 函数 `f1`。注意在非 `macro package` 中无法重导出 `macro package` 的符号36
37
<!-- compile -macro5 -->38
<!-- cfg="--output-type=dylib -o libB.so" -->39
40
```cangjie41
package B42
// public import A.* // Error, it is not allowed to re-export a macro package in a package.43
44
public func f1(input: Int64): Int64 {45
return input46
}47
```48
49
编译命令如下,这里选择使用 `--output-type` 选项将 B 包编译成动态库。50
51
```shell52
cjc B.cj --output-type=dylib -o libB.so53
```54
55
- 在宏包 C 中定义宏 `M2`,依赖了 A 包和 B 包的内容。可以看到 `macro package` 中可以重导出 `macro package` 和非 `macro package` 的符号56
57
<!-- compile -macro5 -->58
<!-- cfg="--compile-macro -L. -lB" -->59
60
```cangjie61
macro package C62
public import A.* // correct: macro package is allowed to re-export in a macro package.63
public import B.* // correct: non-macro package is also allowed to re-export in a macro package.64
import std.ast.*65
66
public macro M2(input: Tokens): Tokens {67
return @M1(input) + Token(TokenKind.NL) + quote(f1(1))68
}69
```70
71
编译命令如下,注意这里需要显式链接 B 包动态库:72
73
```bash74
cjc C.cj --compile-macro -L. -lB75
```76
77
- 在 `main.cj` 中使用 `M2` 宏78
79
<!-- compile -macro5 -->80
<!-- cfg="-L. -lB" -->81
82
```cangjie83
import C.*84
85
main() {86
@M2(let a = 1)87
}88
```89
90
编译命令如下:91
92
```shell93
cjc main.cj -o main -L. -lB94
```95
96
`main.cj`中 `M2` 宏展开后的结果如下:97
98
<!-- code_no_check -->99
100
```cangjie101
import C.*102
103
main() {104
let a = 1105
f1(1)106
}107
```108
109
可以看到 `main.cj` 中出现了来自于 B 包的符号 `f1`。宏的编写者可以在 C 包中重导出 B 包里的符号,这样宏的使用者仅需导入宏包,就可以正确地编译宏展开后的代码。如果在 `main.cj` 中仅使用 `import C.M2` 导入宏符号,则会报 `undeclared identifier 'f1'` 的错误信息。Code 1 · cangjie
1
// file define.cj2
macro package define // 编译 define.cjo 携带 macro 属性3
import std.ast.*4
5
public func A() {} // Error, 宏包不允许定义外部可见的非宏定义,此处会报错6
7
public macro M(input: Tokens): Tokens { // macro M 外部可见8
return input9
}