@@ -181,7 +181,7 @@ defmodule Kernel.ParallelCompiler do
181
181
{ :ok , [ atom ] , [ warning ] | info ( ) }
182
182
| { :error , [ error ] | [ Code . diagnostic ( :error ) ] , [ warning ] | info ( ) }
183
183
def compile_to_path ( files , path , options \\ [ ] ) when is_binary ( path ) and is_list ( options ) do
184
- spawn_workers ( files , { :compile , path } , options )
184
+ spawn_workers ( files , { :compile , path } , Keyword . put ( options , :dest , path ) )
185
185
end
186
186
187
187
@ doc """
@@ -320,6 +320,9 @@ defmodule Kernel.ParallelCompiler do
320
320
end
321
321
322
322
defp write_module_binaries ( result , { :compile , path } , timestamp ) do
323
+ File . mkdir_p! ( path )
324
+ Code . prepend_path ( path )
325
+
323
326
Enum . flat_map ( result , fn
324
327
{ { :module , module } , binary } when is_binary ( binary ) ->
325
328
full_path = Path . join ( path , Atom . to_string ( module ) <> ".beam" )
@@ -420,8 +423,8 @@ defmodule Kernel.ParallelCompiler do
420
423
421
424
try do
422
425
case output do
423
- { :compile , path } -> compile_file ( file , path , parent )
424
- :compile -> compile_file ( file , dest , parent )
426
+ { :compile , _ } -> compile_file ( file , dest , false , parent )
427
+ :compile -> compile_file ( file , dest , true , parent )
425
428
:require -> require_file ( file , parent )
426
429
end
427
430
catch
@@ -527,9 +530,9 @@ defmodule Kernel.ParallelCompiler do
527
530
wait_for_messages ( [ ] , spawned , waiting , files , result , warnings , errors , state )
528
531
end
529
532
530
- defp compile_file ( file , path , parent ) do
533
+ defp compile_file ( file , path , force_load? , parent ) do
531
534
:erlang . process_flag ( :error_handler , Kernel.ErrorHandler )
532
- :erlang . put ( :elixir_compiler_dest , path )
535
+ :erlang . put ( :elixir_compiler_dest , { path , force_load? } )
533
536
:elixir_compiler . file ( file , & each_file ( & 1 , & 2 , parent ) )
534
537
end
535
538
@@ -630,19 +633,28 @@ defmodule Kernel.ParallelCompiler do
630
633
state
631
634
)
632
635
633
- { :module_available , child , ref , file , module , binary } ->
636
+ { :module_available , child , ref , file , module , binary , loaded? } ->
634
637
state . each_module . ( file , module , binary )
635
638
639
+ available =
640
+ case Map . get ( result , { :module , module } ) do
641
+ [ _ | _ ] = pids ->
642
+ loaded? or load_module ( module , binary , state )
643
+ Enum . map ( pids , & { & 1 , :found } )
644
+
645
+ _ ->
646
+ [ ]
647
+ end
648
+
636
649
# Release the module loader which is waiting for an ack
637
650
send ( child , { ref , :ack } )
638
- { available , result } = update_result ( result , :module , module , binary )
639
651
640
652
spawn_workers (
641
653
available ++ queue ,
642
654
spawned ,
643
655
waiting ,
644
656
files ,
645
- result ,
657
+ Map . put ( result , { :module , module } , binary ) ,
646
658
warnings ,
647
659
errors ,
648
660
state
@@ -660,14 +672,31 @@ defmodule Kernel.ParallelCompiler do
660
672
available_or_pending = Map . get ( result , { kind , on } , [ ] )
661
673
662
674
{ waiting , files , result } =
663
- if not is_list ( available_or_pending ) or on in defining do
664
- send ( child_pid , { ref , :found } )
665
- { waiting , files , result }
666
- else
667
- waiting = Map . put ( waiting , child_pid , { kind , ref , file_pid , on , defining , deadlock } )
668
- files = update_timing ( files , file_pid , :compiling )
669
- result = Map . put ( result , { kind , on } , [ child_pid | available_or_pending ] )
670
- { waiting , files , result }
675
+ cond do
676
+ # TODO: Refactor me
677
+ kind == :struct and is_binary ( Map . get ( result , { :module , on } ) ) and
678
+ not :erlang . module_loaded ( on ) ->
679
+ load_module ( on , Map . get ( result , { :module , on } ) , state )
680
+ send ( child_pid , { ref , :found } )
681
+ { waiting , files , result }
682
+
683
+ # We have the module but it was not loaded yet, so we load it
684
+ kind == :module and is_binary ( available_or_pending ) and not :erlang . module_loaded ( on ) ->
685
+ load_module ( on , available_or_pending , state )
686
+ send ( child_pid , { ref , :found } )
687
+ { waiting , files , result }
688
+
689
+ # Whatever we have is available, return it
690
+ not is_list ( available_or_pending ) or on in defining ->
691
+ send ( child_pid , { ref , :found } )
692
+ { waiting , files , result }
693
+
694
+ # We need to wait for it
695
+ true ->
696
+ waiting = Map . put ( waiting , child_pid , { kind , ref , file_pid , on , defining , deadlock } )
697
+ files = update_timing ( files , file_pid , :compiling )
698
+ result = Map . put ( result , { kind , on } , [ child_pid | available_or_pending ] )
699
+ { waiting , files , result }
671
700
end
672
701
673
702
spawn_workers ( queue , spawned , waiting , files , result , warnings , errors , state )
@@ -755,6 +784,22 @@ defmodule Kernel.ParallelCompiler do
755
784
{ { :error , Enum . reverse ( errors , fun . ( ) ) , info } , state }
756
785
end
757
786
787
+ defp load_module ( module , binary , state ) do
788
+ beam_location =
789
+ case state . dest do
790
+ nil ->
791
+ [ ]
792
+
793
+ dest ->
794
+ :filename . join (
795
+ :elixir_utils . characters_to_list ( dest ) ,
796
+ Atom . to_charlist ( module ) ++ ~c" .beam"
797
+ )
798
+ end
799
+
800
+ :code . load_binary ( module , beam_location , binary )
801
+ end
802
+
758
803
defp update_result ( result , kind , module , value ) do
759
804
available =
760
805
case Map . get ( result , { kind , module } ) do
0 commit comments