Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagate static lib dependencies up the chain #44

Open
deplinenoise opened this issue Sep 29, 2010 · 11 comments
Open

Propagate static lib dependencies up the chain #44

deplinenoise opened this issue Sep 29, 2010 · 11 comments

Comments

@deplinenoise
Copy link
Owner

It would be useful to have static libraries "Depends" work recursively, so

StaticLibrary { Name = "foo", ... }
StaticLibrary { Name = "bar", Depends = { "foo" }, ... }
Program = { Name = "qux", Depends = { "bar" }, ... }

Would automatically link qux with foo.

@uucidl
Copy link
Contributor

uucidl commented Jul 8, 2011

The same appears to be true for ExternalLibrary, which do not let their own dependencies propagate up towards the unit that depends on them.

Contrieved example:

ExternalLibrary {
   Name = "opengl",
   Propagate = {
      Frameworks = { "OpenGL" ; Config = { "macosx-*-*" } }
   }
}

ExternalLibrary {
   Name = "glut",
   Depends = "opengl",
   Propagate = {
      Frameworks = { "GLUT", "Foundation" ; Config = { "macosx-*-*" } }
   }
}

Program {
  Name = "h",
  Depends = "glut",...
}

Results in

gcc -FGLUT -FFoundation -c  -o tundra-output/macosx-gcc-debug-default/__a.out/main.o main.c

@lundmark
Copy link

This also seems to be an issue when having a deeper nested hierarchy, such as:

StaticLibrary { name = "foo" }
StaticLibrary{ name = "bar", Depends = { "foo" }, Propagate = { Depends = {"foo"} } }
StaticLibrary{ name = "bar2", Depends = "bar", Propagate = { Depends = {"bar"} },
Program{ name="myprogram", Depends = "bar2" },

Program myprogram does not link towards foo. The same issue goes for hierarchical propagates when it comes to include-files etc. It would be very nice if propagates actually propagated all the chain instead of just to the first level of parent.

@lundmark
Copy link

This goes for all Propagates such as includes, defines etc.

@deplinenoise
Copy link
Owner Author

Patches are welcome :)

@lundmark
Copy link

This seems to solve the issue for me. It's recursive though, so expensive :/ Perhaps add a flag to the unit for the recursive-functionality?

diff --git a/build/tundra2/scripts/tundra/nodegen.lua b/build/tundra2/scripts/tundra/nodegen.lua
--- a/build/tundra2/scripts/tundra/nodegen.lua
+++ b/build/tundra2/scripts/tundra/nodegen.lua
@@ -94,17 +94,24 @@ function _nodegen:customize_env(env, raw
   -- available for subclasses
 end

-function _nodegen:configure_env(env, deps)
+local resolve_dependencies
+
+function _nodegen:configure_env(env, deps_top)
   local build_id = env:get('BUILD_ID')
   local propagate_blocks = {}
   local decl = self.Decl

-  for _, dep_obj in util.nil_ipairs(deps) do
-    local data = dep_obj.Decl.Propagate
-    if data then
-      propagate_blocks[#propagate_blocks + 1] = data
-    end
+  local function append_deps(deps)
+   for _, dep_obj in util.nil_ipairs(deps) do
+     local data = dep_obj.Decl.Propagate
+     if data then
+       propagate_blocks[#propagate_blocks + 1] = data
+     end
+     local child_deps = resolve_dependencies(decl, dep_obj.Decl.Depends, env)
+     append_deps(child_deps)
+   end
   end
+  append_deps(deps_top)

   local function push_bindings(env_key, data)
     if data then

@lundmark
Copy link

Sorry, I'm not sure if that one included my change on (the new) line 309 where

local function resolve_dependencies(decl, raw_deps, env)

needs to be

function resolve_dependencies(decl, raw_deps, env)

@lundmark
Copy link

Note that this does not fix the #195 - issue regarding double-linkage.

@deplinenoise
Copy link
Owner Author

Thanks, I'll try to look into this change this weekend.

@deplinenoise
Copy link
Owner Author

So, while this change seems fine, I wonder if there's a better way to do this that would fix #44 and this issues together.

Basically dependencies are resolved before propagations happen (from the dependencies), so interactions between propagations and dependencies can't support the case where you have:

  • Static library A (propagates an include path)
  • Static library B, depending on A (propagates an include path)
  • Program C, depending on B but wants to pick up the include path from A as well.

In issue #44, you describe a use case similar to:

  • Static library A
  • Static library B, depending on A
  • Static library C, depending on A
  • Program D, depending on B and C

The issue there is that A is linked in twice with the program.

Am I summing this up correctly?

It seems like any fix we attempt for this would have to support both cases, and only visit each propagate/dependency chain once. But I'm not seeing an obvious solution to that right away.

Thoughts?

@leidegre
Copy link
Contributor

I always thought that it was by design to intentionally not get into that problem (where libraries are linked more than once).

The first solution that came to my mind was to simply track what's to be linked with what per unit, then when it's time to link the a program or shared library, a straightforward set operation is all that's needed to ensure that your left with a distinct set of libraries to link, exactly once. As long as the way you tag libraries doesn't get tangled up in some way -- if path name would be unreliable -- wouldn't that work just fine?

And we're talking about units here as well, aren't we? So that list of things to track should be fairly short.

On second thought, this is way to simple to not already have been considered, I mean, the dependency graph already contains this information, where in lies the difficulty of computing a distinct set of libraries to link, in the final step? Or is it just that you don't want to run a whole pass over the graph (only units really matter, though)?

What am I missing?

@lundmark
Copy link

@deplinenoise: Yeah you're summing it up exactly correctly.

What I've done is that I've changed the static libs to obj-files and if / when I want to generate an external "real" static lib, I create a new unit for that. In order to apply the recursive Propagates I've done the patch that I added above. This works awesome for me because then there is no double-linkage.

It's hard to suggest any other fix than what I've done since I really can't see any other solution to it. Having obj-units instead of static-lib units solved the double-linkage and still allows me to define and customize each unit as I want, since the compilation for the obj-files seem to depend only on the current unit and what has been propagated to that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants