1#!/usr/local/bin/python3.8
2
3# Copyright (C) 2003. Vladimir Prus
4# Distributed under the Boost Software License, Version 1.0.
5# (See accompanying file LICENSE_1_0.txt or copy at
6# http://www.boost.org/LICENSE_1_0.txt)
7
8# Test that the <dll-path> property is correctly set when using
9# <hardcode-dll-paths>true.
10
11import BoostBuild
12
13t = BoostBuild.Tester(use_test_config=False)
14
15# The point of this test is to have exe "main" which uses library "b", which
16# uses library "a". When "main" is built with <hardcode-dll-paths>true, paths
17# to both libraries should be present as values of <dll-path> feature. We
18# create a special target type which reports <dll-path> values on its sources
19# and compare the list of found values with out expectations.
20
21t.write("jamroot.jam", "using dll_paths ;")
22t.write("jamfile.jam", """\
23exe main : main.cpp b//b ;
24explicit main ;
25path-list mp : main ;
26""")
27
28t.write("main.cpp", "int main() {}\n")
29t.write("dll_paths.jam", """\
30import "class" : new ;
31import feature ;
32import generators ;
33import print ;
34import sequence ;
35import type ;
36
37rule init ( )
38{
39    type.register PATH_LIST : pathlist ;
40
41    class dll-paths-list-generator : generator
42    {
43        rule __init__ ( )
44        {
45            generator.__init__ dll_paths.list : EXE : PATH_LIST ;
46        }
47
48        rule generated-targets ( sources + : property-set : project name ? )
49        {
50            local dll-paths ;
51            for local s in $(sources)
52            {
53                local a = [ $(s).action ] ;
54                if $(a)
55                {
56                    local p = [ $(a).properties ] ;
57                    dll-paths += [ $(p).get <dll-path> ] ;
58                }
59            }
60            return [ generator.generated-targets $(sources) :
61                [ $(property-set).add-raw $(dll-paths:G=<dll-path>) ] :
62                $(project) $(name) ] ;
63        }
64    }
65    generators.register [ new dll-paths-list-generator ] ;
66}
67
68rule list ( target : sources * : properties * )
69{
70    local paths = [ feature.get-values <dll-path> : $(properties) ] ;
71    paths = [ sequence.insertion-sort $(paths) ] ;
72    print.output $(target) ;
73    print.text $(paths) ;
74}
75""")
76
77t.write("dll_paths.py", """\
78import bjam
79
80import b2.build.type as type
81import b2.build.generators as generators
82
83from b2.manager import get_manager
84
85def init():
86    type.register("PATH_LIST", ["pathlist"])
87
88    class DllPathsListGenerator(generators.Generator):
89
90        def __init__(self):
91            generators.Generator.__init__(self, "dll_paths.list", False,
92                ["EXE"], ["PATH_LIST"])
93
94        def generated_targets(self, sources, ps, project, name):
95            dll_paths = []
96            for s in sources:
97                a = s.action()
98                if a:
99                    p = a.properties()
100                    dll_paths += p.get('dll-path')
101            dll_paths.sort()
102            return generators.Generator.generated_targets(self, sources,
103                ps.add_raw(["<dll-path>" + p for p in dll_paths]), project,
104                name)
105
106    generators.register(DllPathsListGenerator())
107
108command = \"\"\"
109echo $(PATHS) > $(<[1])
110\"\"\"
111def function(target, sources, ps):
112    bjam.call('set-target-variable', target, "PATHS", ps.get('dll-path'))
113
114get_manager().engine().register_action("dll_paths.list", command,
115    function=function)
116""")
117
118t.write("a/jamfile.jam", "lib a : a.cpp ;")
119t.write("a/a.cpp", """\
120void
121#if defined(_WIN32)
122__declspec(dllexport)
123#endif
124foo() {}
125""")
126
127t.write("b/jamfile.jam", "lib b : b.cpp ../a//a ;")
128t.write("b/b.cpp", """\
129void
130#if defined(_WIN32)
131__declspec(dllexport)
132#endif
133bar() {}
134""")
135
136t.run_build_system(["hardcode-dll-paths=true"])
137
138t.expect_addition("bin/$toolset/debug*/mp.pathlist")
139
140es1 = t.adjust_name("a/bin/$toolset/debug*")
141es2 = t.adjust_name("b/bin/$toolset/debug*")
142
143t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es1)
144t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es2)
145
146t.rm("bin/$toolset/debug*/mp.pathlist")
147
148# Now run the same checks with pre-built libraries
149adll = t.glob_file("a/bin/$toolset/debug*/a.dll")
150bdll = t.glob_file("b/bin/$toolset/debug*/b.dll")
151t.write("b/jamfile.jam", """
152local bdll = %s ;
153# Make sure that it is found even with multiple source-locations
154project : source-location c $(bdll:D) ;
155lib b : ../a//a : <file>$(bdll:D=) ;
156""" % bdll.replace("\\", "\\\\"))
157t.run_build_system(["hardcode-dll-paths=true"])
158t.expect_addition("bin/$toolset/debug*/mp.pathlist")
159
160t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es1)
161t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es2)
162
163t.cleanup()
164