Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1c9a477
feat: 共有宣言と世代公開を追加
redpeacock78 Jul 14, 2026
773cecb
fix: 世代切替を移植可能にする
redpeacock78 Jul 15, 2026
97688e6
fix: 世代切替後も namespace を保持する
redpeacock78 Jul 15, 2026
ae84f92
fix: desugar の Bash 3.2 互換性を戻す
redpeacock78 Jul 15, 2026
75d1169
fix: 共有型検査と dist 正規化を直す
redpeacock78 Jul 15, 2026
5a9e161
fix: desugar の公開整合性を守る
redpeacock78 Jul 15, 2026
5ba0cf7
fix: include の予約 namespace を拒否する
redpeacock78 Jul 15, 2026
3f89404
fix: vendor 実行と symlink 更新を直す
redpeacock78 Jul 15, 2026
3100de3
fix: app の実行 cwd を保つ
redpeacock78 Jul 15, 2026
e3edbfe
fix: supervised worker の runtime を再利用
redpeacock78 Jul 15, 2026
aca3671
fix: compat symlink の所有権を守る
redpeacock78 Jul 15, 2026
a29364d
fix: compat symlink の所有者を固定する
redpeacock78 Jul 16, 2026
780de69
fix: index 状態と plugin 探索元を正す
redpeacock78 Jul 16, 2026
b724586
fix: HAWK_LIB を子プロセスへ渡す
redpeacock78 Jul 16, 2026
006fe8d
fix: 旧 dist 成果物を symlink へ移行する
redpeacock78 Jul 16, 2026
3260257
fix: marker 所有 directory を早期拒否する
redpeacock78 Jul 16, 2026
7a9516f
fix: 欠落した compat の所有権を守る
redpeacock78 Jul 16, 2026
dcadd8b
fix: stable marker を namespace ごとに分離する
redpeacock78 Jul 16, 2026
41314c0
fix: app と framework の plugin を統合する
redpeacock78 Jul 16, 2026
dbcc13e
fix: 旧2列 compat marker を移行する
redpeacock78 Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions core/plugin.awk
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,30 @@
# config_keys を満たさなかった場合 PLUGIN_REGISTER_ERROR=1 を立てる
# (起動時 main loop が exit 1 で判定する)

function plugin_discover( cmd, pname, func_name, meta) {
cmd = "ls plugins 2>/dev/null"
while ((cmd | getline pname) > 0) {
function plugin_discover( cmd, pname, func_name, meta, root, disabled, dirs, n, i, dir) {
if (ENVIRON["HAWK_PLUGIN_DIRS"] != "") {
n = split(ENVIRON["HAWK_PLUGIN_DIRS"], dirs, "\n")
} else {
root = (ENVIRON["HAWK_LIB"] != "" ? ENVIRON["HAWK_LIB"] : ".") "/plugins"
cmd = "ls " _shellquote(root) " 2>/dev/null"
while ((cmd | getline pname) > 0) {
if (pname == "" || pname ~ /^\./) continue
dirs[++n] = root "/" pname
}
close(cmd)
}
for (i = 1; i <= n; i++) {
dir = dirs[i]
sub(/\/+$/, "", dir)
pname = dir
sub(/^.*\//, "", pname)
if (pname == "" || pname ~ /^\./) continue
if ((getline _ < ("plugins/" pname "/.disabled")) >= 0) {
close("plugins/" pname "/.disabled")
disabled = dir "/.disabled"
if ((getline _ < disabled) >= 0) {
close(disabled)
continue
}
close("plugins/" pname "/.disabled")
close(disabled)

func_name = "plugin_" pname "_manifest"
delete meta
Expand All @@ -36,7 +51,6 @@ function plugin_discover( cmd, pname, func_name, meta) {
@func_name(meta)
plugin_register(pname, meta)
}
close(cmd)
}

function plugin_register(pname, meta, keys, n, j, hooks, m, hook_name, k) {
Expand Down
2 changes: 2 additions & 0 deletions docs/ja/plugins.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

`plugins/<name>/` にプラグインディレクトリを配置すると、H-awk が起動時に自動発見してロードします。

H-awk は `$HAWK_LIB/plugins`(framework 側)と `./plugins`(アプリの作業ディレクトリ)の両方からプラグインをロードします。同名プラグインが両方にある場合はアプリ側が優先され、アプリ側に `.disabled` があれば同名の framework 側プラグインも無効になります。

```awk
# plugins/logger/manifest.awk
function plugin_logger_manifest(meta) {
Expand Down
2 changes: 2 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

Drop a plugin directory into `plugins/<name>/`. H-awk auto-discovers and loads plugins at startup.

H-awk loads plugins from both `$HAWK_LIB/plugins` (the framework) and `./plugins` (the app working directory). If both contain the same plugin name, the app plugin wins; an app-side `.disabled` also shadows and disables the framework plugin of that name.

```awk
# plugins/logger/manifest.awk
function plugin_logger_manifest(meta) {
Expand Down
33 changes: 33 additions & 0 deletions dsl/check.awk
Original file line number Diff line number Diff line change
Expand Up @@ -1887,11 +1887,13 @@ function v2_prescan_expr_type(id, kind, name, inner, ret_sig, typearg) {

function v2_check() {
v2_init_builtins()
v2_merge_shared()
VARIANTS["Result"] = "ok" SUBSEP "ng"
VARIANTS["Option"] = "some" SUBSEP "none"

v2_collect_raw_funcs()
v2_collect(1)
v2_check_shared_consistency()
v2_infer_unannotated_returns(1)
v2_check_alias_cycles()
v2_check_record_return_type(1)
Expand All @@ -1906,6 +1908,37 @@ function v2_check() {
v2_check_mut(1)
}

function v2_check_shared_consistency( k) {
for (k in V2_SHARED_ALIAS)
if (ALIAS[k] != V2_SHARED_ALIAS[k]) v2_diag(1, 1, "conflicting shared type alias: " k)
for (k in V2_SHARED_SIG)
if (SIG[k] != V2_SHARED_SIG[k]) v2_diag(1, 1, "conflicting shared function signature")
for (k in V2_SHARED_RECORD_FIELDS)
if (V2_RECORD_FIELDS[k] != V2_SHARED_RECORD_FIELDS[k]) v2_diag(1, 1, "conflicting shared record field")
}

function v2_merge_shared( k, p) {
for (k in V2_SHARED_ALIAS) {
if ((k in ALIAS) && ALIAS[k] != V2_SHARED_ALIAS[k])
v2_diag(1, 1, "conflicting shared type alias: " k)
ALIAS[k] = V2_SHARED_ALIAS[k]
}
for (k in V2_SHARED_SIG) {
split(k, p, SUBSEP)
if ((k in SIG) && SIG[k] != V2_SHARED_SIG[k])
v2_diag(1, 1, "conflicting shared function signature: " p[1])
SIG[k] = V2_SHARED_SIG[k]
}
for (k in V2_SHARED_RECORD_TYPE) V2_RECORD_TYPE[k] = 1
for (k in V2_SHARED_RECORD_FIELDS) {
split(k, p, SUBSEP)
if ((k in V2_RECORD_FIELDS) && V2_RECORD_FIELDS[k] != V2_SHARED_RECORD_FIELDS[k])
v2_diag(1, 1, "conflicting shared record field: " p[1] "." p[2])
V2_RECORD_FIELDS[k] = V2_SHARED_RECORD_FIELDS[k]
}
for (k in V2_SHARED_RAW_FUNC) V2_RAW_FUNC[k] = 1
}

# LET/LETQ の直接の初期化式(最後の子)だけが空コレクションリテラル
# []/{} を受け付けられる(v2_e_let はこの位置しかハンドルしない)。
# v2_check_bare_collection_lit より前に呼び、当該 id を許可集合に登録する。
Expand Down
12 changes: 12 additions & 0 deletions dsl/desugar.awk
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
BEGIN {
V2_SRC = (ARGC > 1) ? ARGV[1] : "/dev/stdin"
V2_ERRORS = 0
v2_merge_shared_pre_rpn()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Seed lexing before shared-call checks

When an included file provides a typed function and the entry calls it from an otherwise raw AWK function, this merge point is too late: v2_lex has already built the function-call detector without the shared signatures, so the call line stays RAWLINE and skips v2_check_calls. For example, with lib.awk defining function normalize(x: Str) -> Str and main.awk containing function caller() { return normalize(1) }, hawk-libs desugar exits 0, whereas the same declarations in one file correctly report the Str/Int mismatch.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

対応しました。v2_merge_shared_pre_rpn() の呼び出しを v2_lex() の前に移し、マージ対象を V2_SHARED_SIG / V2_SHARED_ALIAS / V2_SHARED_RAW_FUNC にも拡張しています(従来は record 型/フィールドのみで、しかも lex の後というタイミングも誤っていました)。テスト shared_signature_checks_raw_caller(include 先の normalize(x: Str) -> Str を raw AWK の caller が normalize(123) で呼ぶ型不一致が検出されること)を追加しています。

v2_lex(V2_SRC)
if (V2_DUMP == "lex") { v2_dump_lex(); exit(V2_ERRORS ? 1 : 0) }
v2_rpn()
Expand All @@ -27,6 +28,17 @@ BEGIN {
exit(V2_ERRORS ? 1 : 0)
}

function v2_merge_shared_pre_rpn( k, p) {
for (k in V2_SHARED_ALIAS) ALIAS[k] = V2_SHARED_ALIAS[k]
for (k in V2_SHARED_SIG) SIG[k] = V2_SHARED_SIG[k]
for (k in V2_SHARED_RECORD_TYPE) V2_RECORD_TYPE[k] = 1
for (k in V2_SHARED_RECORD_FIELDS) {
split(k, p, SUBSEP)
V2_RECORD_FIELDS[p[1], p[2]] = V2_SHARED_RECORD_FIELDS[k]
}
for (k in V2_SHARED_RAW_FUNC) V2_RAW_FUNC[k] = 1
}

function v2_dump_lex( i) { for (i = 1; i <= TOK["n"]; i++) printf "%d\t%s\t%d\t%d\t%s\n", i, TOK[i,"kind"], TOK[i,"line"], TOK[i,"col"], TOK[i,"text"] }
function v2_dump_rpn( i) { for (i = 1; i <= RPN["n"]; i++) printf "%d\t%s\t%d\t%s\t%s\n", i, RPN[i,"kind"], RPN[i,"line"], RPN[i,"val"], ((RPN[i,"kind"]=="CALL") ? RPN[i,"arity"] : "") }
function v2_dump_ast( id, k, cs) { for (id = 1; id <= V2_NAST; id++) { cs = ""; for (k = 1; k <= AST[id,"nc"]; k++) cs = cs ((k>1)?",":"") AST[id,"c" k]; printf "%d\t%s\t%d\t%d\t%s\t%s\n", id, AST[id,"kind"], AST[id,"line"], AST[id,"nc"], cs, AST[id,"text"] } }
Expand Down
99 changes: 99 additions & 0 deletions dsl/index.awk
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# SPDX-License-Identifier: MIT
@include "dsl/util.awk"
@include "dsl/lex.awk"
@include "dsl/rpn.awk"
@include "dsl/parse.awk"
@include "dsl/check.awk"

function q(s) {
gsub(/\\/, "\\\\", s)
gsub(/"/, "\\\"", s)
return "\"" s "\""
}

function emit_shared(out, k, p, n, v) {
print "BEGIN {" > out
for (k in V2_RECORD_TYPE)
printf " V2_SHARED_RECORD_TYPE[%s] = 1\n", q(k) > out
for (k in V2_RECORD_FIELDS) {
split(k, p, SUBSEP)
printf " V2_SHARED_RECORD_FIELDS[%s, %s] = %s\n", q(p[1]), q(p[2]), q(V2_RECORD_FIELDS[k]) > out
}
for (k in ALIAS)
printf " V2_SHARED_ALIAS[%s] = %s\n", q(k), q(ALIAS[k]) > out
for (k in SIG) {
split(k, p, SUBSEP)
printf " V2_SHARED_SIG[%s, %s] = %s\n", q(p[1]), q(p[2]), q(SIG[k]) > out
}
for (k in V2_RAW_FUNC)
printf " V2_SHARED_RAW_FUNC[%s] = 1\n", q(k) > out
print "}" > out
}

BEGIN {
if (V2_INDEX_LIST == "") exit 1
V2_INDEX_MODE = 1
n = split(V2_INDEX_LIST, files, SUBSEP)
for (i = 1; i <= n; i++) {
if (files[i] == "") continue
delete V2_INDEX_RUN_FIELDS
delete V2_INDEX_RUN_RECORDS
delete V2_INDEX_OLD_FIELDS
for (k in V2_INDEX_RECORD_FIELDS) V2_INDEX_OLD_FIELDS[k] = V2_INDEX_RECORD_FIELDS[k]
delete V2_INDEX_OLD_RECORDS
for (k in V2_INDEX_RECORD_NAMES) V2_INDEX_OLD_RECORDS[k] = 1
v2_lex(files[i])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reset lexer state between indexed files

This loop indexes every file in a single gawk process, but v2_lex() does not clear per-file line state such as V2_FORCE_DSL before reading the next file. When an earlier file has an unannotated DSL function covering lines 1-4, those line numbers remain forced for a later include that is otherwise raw AWK; the index can then emit a typed SIG for that raw function, causing a sibling raw caller like raw(1, 2) to fail desugar with an arity error instead of staying raw as before. Clear the per-file lexer arrays before each v2_lex() call or inside v2_lex().

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 780de69.

v2_lex() の先頭で TOK / PASS / V2_RAWLINE / V2_LINE_TEXT / V2_FORCE_DSL を delete してから走らせるようにしました。以前は V2_FORCE_DSL がクリアされず、あるファイルで force-mark された行番号が後続ファイルの同じ行番号帯に漏れて誤って DSL 扱いされる状態でした。

回帰テスト index_lex_state_isolated_per_file を追加:1〜4行目にDSL構文を含む未注釈関数を持つファイルAの後に、同じ行番号帯にraw AWK関数raw(a, b)を持つファイルBをindexし、rawがV2_SHARED_SIGに誤登録されないこと、および実際にcaller() { return raw(1, 2) }のdesugarが成功することを検証しています。

v2_rpn()
for (k in V2_RECORD_FIELDS) {
if ((k in V2_INDEX_RECORD_FIELDS) && V2_INDEX_RECORD_FIELDS[k] != V2_RECORD_FIELDS[k]) {
print "[hawk-libs] index failed: conflicting record field definition" > "/dev/stderr"
exit 1
}
V2_INDEX_RECORD_FIELDS[k] = V2_RECORD_FIELDS[k]
}
for (k in V2_INDEX_OLD_FIELDS) {
split(k, p, SUBSEP)
if ((p[1] in V2_INDEX_RUN_RECORDS) && !(k in V2_INDEX_RUN_FIELDS)) {
print "[hawk-libs] index failed: conflicting record field definition" > "/dev/stderr"
exit 1
}
}
for (k in V2_INDEX_RUN_FIELDS) {
split(k, p, SUBSEP)
if ((p[1] in V2_INDEX_OLD_RECORDS) && !(k in V2_INDEX_OLD_FIELDS)) {
print "[hawk-libs] index failed: conflicting record field definition" > "/dev/stderr"
exit 1
}
}
for (k in V2_INDEX_RUN_RECORDS) {
if (k in V2_INDEX_ALIAS) {
print "[hawk-libs] index failed: type name is both record and alias: " k > "/dev/stderr"
exit 1
}
V2_INDEX_RECORD_NAMES[k] = 1
}
v2_parse()
v2_collect(1)
v2_collect_raw_funcs()
for (k in ALIAS) {
if (k in V2_INDEX_RECORD_NAMES) {
print "[hawk-libs] index failed: type name is both record and alias: " k > "/dev/stderr"
exit 1
}
if ((k in V2_INDEX_ALIAS) && V2_INDEX_ALIAS[k] != ALIAS[k]) {
print "[hawk-libs] index failed: conflicting type alias definition: " k > "/dev/stderr"
exit 1
}
V2_INDEX_ALIAS[k] = ALIAS[k]
Comment on lines +78 to +87

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject alias/record name collisions

When one file in the include closure defines type User = { ... } and another defines type User = Str, the index accepts both because aliases are only compared against prior aliases, not record names. The generated shared environment then contains both V2_SHARED_RECORD_TYPE["User"] and V2_SHARED_ALIAS["User"], so record literals in the record file can be lowered as the scalar alias and the published AWK fails at runtime (e.g. attempt to use scalar parameter ... as an array) instead of failing closed during indexing.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

対応しました。record 登録時に同名が既存 alias にあれば拒否、alias 登録時に同名が既存/現在の record にあれば拒否と、両方向の衝突を index 時点で fail closed にしています。テスト alias_record_name_collision_rejected(include 順を正逆とも検証)を追加しています。

}
for (k in SIG) {
if ((k in V2_INDEX_SIG) && V2_INDEX_SIG[k] != SIG[k]) {
print "[hawk-libs] index failed: conflicting function signature: " k > "/dev/stderr"
exit 1
}
V2_INDEX_SIG[k] = SIG[k]
}
}
emit_shared(V2_INDEX_OUT)
exit 0
}
20 changes: 16 additions & 4 deletions dsl/lex.awk
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function v2_strip_str_comment(line, i, ch, out, instr) {
}

# DSL 構文を含む行か判定する述語
# type NAME = ... 宣言をファイル全体から事前収集し、型注釈検出(v2_is_dsl の
# type NAME = ... 宣言を共有 index とファイル全体から事前収集し、型注釈検出(v2_is_dsl の
# `: TYPE` 判定)に使う代替パターンを組み立てる(CE)。組込み型集合に無い
# ユーザー定義エイリアスだけが注釈に使われている関数(`type Status = Int|Str`
# + `function f(x: Status) {...}`)は、この事前収集なしでは検出できず素の awk
Expand All @@ -72,8 +72,11 @@ function v2_strip_str_comment(line, i, ch, out, instr) {
# 誤検出リスク: エイリアス名が偶然コメント・文字列中の識別子と一致するケースは
# 元々の固定型リストと同じ理由で許容する(v2_strip_str_comment 済みの行に対して
# のみ判定するため文字列内は対象外)。
function v2_collect_type_aliases(nlines, i, s, m, names, n) {
function v2_collect_type_aliases(nlines, i, s, m, names, n, k) {
names = ""; n = 0
for (k in V2_SHARED_ALIAS) {
if (!(k in V2_DSL_ALIAS)) { V2_DSL_ALIAS[k] = 1; names = names (n++ ? "|" : "") k }
}
for (i = 1; i <= nlines; i++) {
s = v2_strip_str_comment(V2_RAWLINE[i])
if (match(s, /(^|[^[:alnum:]_])type[[:space:]]+([A-Za-z_][A-Za-z0-9_]*)[[:space:]]*=/, m)) {
Expand All @@ -83,14 +86,18 @@ function v2_collect_type_aliases(nlines, i, s, m, names, n) {
V2_ALIAS_TYPEANN_RE = names
}

# 戻り値型注釈(`-> RETTYPE`)を持つユーザー定義関数名をファイル全体から
# 戻り値型注釈(`-> RETTYPE`)を持つユーザー定義関数名を共有 index とファイル全体から
# 事前収集する(review EQ)。DSL マーカーを一切持たない関数本体
# (`function handler() { normalize(123) }`)でも、本体が既知の注釈付き
# 関数を呼び出しているだけなら v1 は引数型検査を行う。v2 は関数ヘッダに
# DSL 構文が無いと本体全体を素通し(RAWLINE)扱いにするため、この呼び出し
# だけが v2_check_calls の CALL 検査を経由せず引数型不一致を見逃していた。
function v2_collect_annotated_funcs(nlines, i, s, m, names, n) {
function v2_collect_annotated_funcs(nlines, i, s, m, names, n, k, p) {
names = ""; n = 0
for (k in V2_SHARED_SIG) {
split(k, p, SUBSEP)
if (!(p[1] in V2_DSL_FUNCNAME)) { V2_DSL_FUNCNAME[p[1]] = 1; names = names (n++ ? "|" : "") p[1] }
}
for (i = 1; i <= nlines; i++) {
s = v2_strip_str_comment(V2_RAWLINE[i])
# 戻り値注釈 (-> RETTYPE) を持つ関数
Expand Down Expand Up @@ -235,6 +242,11 @@ function v2_mark_unannotated_func(nlines, i, j, k, depth, stripped, tmp, n_op
# トークン化する(BQ)。{ を含む行を処理したら解除する。
function v2_lex(src, line, lineno, in_when, in_block, nlines, tok_start, k, \
pending_brace, header_stripped, force_line) {
delete TOK
delete PASS
delete V2_RAWLINE
delete V2_LINE_TEXT
delete V2_FORCE_DSL
V2_NLINES = 0
TOK["n"] = 0
in_when = 0
Expand Down
3 changes: 3 additions & 0 deletions dsl/rpn.awk
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ function v2_rpn_typedecl(i, line, name, j, typestart, typetext) {
if (j <= TOK["n"] && TOK[j,"kind"] == "OP" && TOK[j,"text"] == "=" && \
TOK[j+1,"kind"] == "LBRACE") {
V2_RECORD_TYPE[name] = 1
if (V2_INDEX_MODE) V2_INDEX_RUN_RECORDS[name] = 1
return v2_rpn_record_fields(name, j + 1)
}

Expand Down Expand Up @@ -899,6 +900,7 @@ function v2_rpn_record_fields(typename, open_pos, j, fname, typestart, typete
for (k = typestart; k < j; k++)
typetext = typetext ((TOK[k,"kind"] == "COMMA") ? ", " : TOK[k,"text"])
V2_RECORD_FIELDS[typename, fname] = typetext
if (V2_INDEX_MODE) V2_INDEX_RUN_FIELDS[typename, fname] = typetext
if (TOK[j,"kind"] == "COMMA") j++ # inline 形の区切り
}
# v1 は record 宣言ブロック全体と直後の空行 1 行をまとめてスキップし、
Expand Down Expand Up @@ -1490,6 +1492,7 @@ function v2_rpn( i) {
# ファイル先頭から順に埋める。プログラム全体で 1 つの表(関数スコープでは
# クリアしない)。
delete V2_RPN_ALIAS
for (i in V2_SHARED_ALIAS) V2_RPN_ALIAS[i] = V2_SHARED_ALIAS[i]

v2_rpn_prescan_records()

Expand Down
2 changes: 1 addition & 1 deletion libexec/hawk-check
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -e

HAWK_LIB="${HAWK_LIB:-$(cd "$(dirname "$0")/.." && pwd)}"
export HAWK_LIB="${HAWK_LIB:-$(cd "$(dirname "$0")/.." && pwd)}"
HAWK_LIBEXEC="${HAWK_LIBEXEC:-$(cd "$(dirname "$0")" && pwd)}"
LIBS="${HAWK_LIBEXEC}/hawk-libs"

Expand Down
2 changes: 1 addition & 1 deletion libexec/hawk-emit
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -e

HAWK_LIB="${HAWK_LIB:-$(cd "$(dirname "$0")/.." && pwd)}"
export HAWK_LIB="${HAWK_LIB:-$(cd "$(dirname "$0")/.." && pwd)}"
HAWK_LIBEXEC="${HAWK_LIBEXEC:-$(cd "$(dirname "$0")" && pwd)}"
LIBS="${HAWK_LIBEXEC}/hawk-libs"

Expand Down
Loading
Loading