Skip to content

Commit bb6c95c

Browse files
committed
Prefer start module option to heuristics
Useful for defining a start module that doesn't have start/0 (but main/1). Signed-off-by: Paul Guyot <[email protected]>
1 parent 89cce99 commit bb6c95c

File tree

3 files changed

+64
-14
lines changed

3 files changed

+64
-14
lines changed

src/packbeam_api.erl

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ create(OutputPath, InputPaths, ApplicationModule, Prune, StartModule) ->
216216
list(InputPath) ->
217217
case file_type(InputPath) of
218218
avm ->
219-
parse_file(InputPath, false);
219+
parse_file(InputPath, undefined, false);
220220
_ ->
221221
throw(io_lib:format("Expected AVM file: ~p", [InputPath]))
222222
end.
@@ -244,7 +244,7 @@ list(InputPath) ->
244244
extract(InputPath, AVMElementNames, OutputDir) ->
245245
case file_type(InputPath) of
246246
avm ->
247-
ParsedFiles = parse_file(InputPath, false),
247+
ParsedFiles = parse_file(InputPath, undefined, false),
248248
write_files(filter_names(AVMElementNames, ParsedFiles), OutputDir);
249249
_ ->
250250
throw(io_lib:format("Expected AVM file: ~p", [InputPath]))
@@ -271,7 +271,7 @@ extract(InputPath, AVMElementNames, OutputDir) ->
271271
delete(OutputPath, InputPath, AVMElementNames) ->
272272
case file_type(InputPath) of
273273
avm ->
274-
ParsedFiles = parse_file(InputPath, false),
274+
ParsedFiles = parse_file(InputPath, undefined, false),
275275
write_packbeam(OutputPath, remove_names(AVMElementNames, ParsedFiles));
276276
_ ->
277277
throw(io_lib:format("Expected AVM file: ~p", [InputPath]))
@@ -341,7 +341,7 @@ get_flags(AVMElement) ->
341341
parse_files(InputPaths, StartModule, IncludeLines) ->
342342
Files = lists:foldl(
343343
fun(InputPath, Accum) ->
344-
Accum ++ parse_file(InputPath, IncludeLines)
344+
Accum ++ parse_file(InputPath, StartModule, IncludeLines)
345345
end,
346346
[],
347347
InputPaths
@@ -354,10 +354,10 @@ parse_files(InputPaths, StartModule, IncludeLines) ->
354354
end.
355355

356356
%% @private
357-
parse_file({InputPath, ModuleName}, IncludeLines) ->
358-
parse_file(file_type(InputPath), ModuleName, load_file(InputPath), IncludeLines);
359-
parse_file(InputPath, IncludeLines) ->
360-
parse_file(file_type(InputPath), InputPath, load_file(InputPath), IncludeLines).
357+
parse_file({InputPath, ModuleName}, StartModule, IncludeLines) ->
358+
parse_file(file_type(InputPath), ModuleName, StartModule, load_file(InputPath), IncludeLines);
359+
parse_file(InputPath, StartModule, IncludeLines) ->
360+
parse_file(file_type(InputPath), InputPath, StartModule, load_file(InputPath), IncludeLines).
361361

362362
%% @private
363363
file_type(InputPath) ->
@@ -595,18 +595,25 @@ filter_modules(Modules, ParsedFiles) ->
595595
).
596596

597597
%% @private
598-
parse_file(beam, _ModuleName, Data, IncludeLines) ->
598+
parse_file(beam, _ModuleName, StartModule, Data, IncludeLines) ->
599599
{ok, Module, Chunks} = beam_lib:all_chunks(Data),
600600
{UncompressedChunks, UncompressedLiterals} = maybe_uncompress_literals(Chunks),
601601
FilteredChunks = filter_chunks(UncompressedChunks, IncludeLines),
602602
{ok, Binary} = beam_lib:build_module(FilteredChunks),
603603
{ok, {Module, ChunkRefs}} = beam_lib:chunks(Data, [imports, exports, atoms]),
604604
Exports = proplists:get_value(exports, ChunkRefs),
605605
Flags =
606-
case lists:member({start, 0}, Exports) of
607-
true ->
606+
if
607+
StartModule =:= Module ->
608608
?BEAM_CODE_FLAG bor ?BEAM_START_FLAG;
609-
_ ->
609+
StartModule =:= undefined ->
610+
case lists:member({start, 0}, Exports) of
611+
true ->
612+
?BEAM_CODE_FLAG bor ?BEAM_START_FLAG;
613+
_ ->
614+
?BEAM_CODE_FLAG
615+
end;
616+
true ->
610617
?BEAM_CODE_FLAG
611618
end,
612619
[
@@ -619,14 +626,14 @@ parse_file(beam, _ModuleName, Data, IncludeLines) ->
619626
{uncompressed_literals, UncompressedLiterals}
620627
]
621628
];
622-
parse_file(avm, ModuleName, Data, _IncludeLines) ->
629+
parse_file(avm, ModuleName, _StartModule, Data, _IncludeLines) ->
623630
case Data of
624631
<<?AVM_HEADER, AVMData/binary>> ->
625632
parse_avm_data(AVMData);
626633
_ ->
627634
throw(io_lib:format("Invalid AVM header: ~p", [ModuleName]))
628635
end;
629-
parse_file(normal, ModuleName, Data, _IncludeLines) ->
636+
parse_file(normal, ModuleName, _StartModule, Data, _IncludeLines) ->
630637
DataSize = byte_size(Data),
631638
Blob = <<DataSize:32, Data/binary>>,
632639
[[{element_name, ModuleName}, {flags, ?NORMAL_FILE_FLAG}, {data, Blob}]].

test/g.erl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
% Copyright 2025 Paul Guyot <[email protected]>
2+
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
3+
4+
-module(g).
5+
6+
-export([main/1]).
7+
8+
main(_Args) ->
9+
c:test().

test/test_packbeam.erl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,40 @@ packbeam_create_start_test() ->
112112

113113
ok.
114114

115+
packbeam_create_start_main_test() ->
116+
AVMFile = dest_dir("packbeam_create_start_main_test.avm"),
117+
?assertMatch(
118+
ok,
119+
packbeam_api:create(
120+
AVMFile,
121+
[
122+
test_beam_path("c.beam"),
123+
test_beam_path("f.beam"),
124+
test_beam_path("g.beam")
125+
],
126+
false,
127+
g
128+
)
129+
),
130+
131+
ParsedFiles = packbeam_api:list(AVMFile),
132+
133+
?assert(is_list(ParsedFiles)),
134+
?assertEqual(length(ParsedFiles), 3),
135+
136+
[GFile | _] = ParsedFiles,
137+
138+
% io:format(user, "~p~n", [ParsedFiles]),
139+
140+
?assertMatch(g, get_module(GFile)),
141+
?assertMatch("g.beam", get_module_name(GFile)),
142+
?assert(is_beam(GFile)),
143+
?assert(is_start(GFile)),
144+
?assert(lists:member({main, 1}, get_exports(GFile))),
145+
?assert(not lists:member({start, 0}, get_exports(GFile))),
146+
147+
ok.
148+
115149
packbeam_create_prune_test() ->
116150
AVMFile = dest_dir("packbeam_create_prune_test.avm"),
117151
?assertMatch(

0 commit comments

Comments
 (0)