Search Unity

Optional package dependencis?

Discussion in 'Package Manager' started by jwvanderbeck, Jul 31, 2019.

  1. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    I had posted this earlier in the general editor forum, but it was suggested I post it here instead. Original post follows :)

    How can I set up something so that one package depends on and uses another package but only if that other package is present. In other words that second package is optional and extends functionality if present. If it is not present, the first package can still run without it.

    The "old" way I could do this using #define conditionals, but with packages it seems more complicated because you have to define the dependencies
     
  2. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    Hi @jwvanderbeck,

    Please take a look at the Version defines section of https://docs.unity3d.com/Manual/ScriptCompilationAssemblyDefinitionFiles.html. I think it should do what you want. You do not need to define a dependency in the package.json, otherwise the dependency will not be optional (as you have probably guessed).
     
    tteneder likes this.
  3. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Hi, thanks for the reply. I did read that section but to be honest it didn't completely make sense to me. Maybe I need to revisit it and just play with it in the editor to see what happens.
     
  4. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    The idea is that the asmdefs in your own package can list defines that are enabled automatically when the specified package is present and it's version matches the version range you specify. This gives you control over the define name, and avoids clashes with the same names in other packages, all the while requiring no interaction on the part of the other package developer.
     
  5. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    That sounds about what we want. I'll play around with it once I get back from Siggraph. Thank you for the insight!
     
    maximeb_unity likes this.
  6. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Ok so I'm back and taking a look at this now, but running into an immediate problem in that the Version Defines section isn't even showing up in my asmdef's inspector. I'm pretty sure I saw it there before so I'm not sure why it is gone now. Does it only show up under certain preconditions or only in certain Unity versions? I'm working in a couple different versions of the editor including 2018.3 and 2019.2.
     
  7. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    As far as I know, this is a 2019.2+ feature. There's nothing specific that needs to be done to make it show up.
     
  8. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Hi, wanted to loop back to this. I finally got a chance to work with this in Unity 2019.3 and it isn't quite working as expected.

    I setup a define to look for com.unity.mathematics and that define does properly propagate into my package, so its set when Mathematics is present, and unset when it isn't. So far so good.

    However, when it is set, the actual assembly, com.unity.mathematics doesn't get added as a dependency so I can't actually access it. I can manually set it as a dependency, but then that defeats the purpose.
     
  9. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,644
    I am not 100% sure if I got your problem right, but that option enables optional defines so that the compiler can compile different portion of code depending if the assembly is present or not. It seems that you instead want dependencies to be downloaded optionally depending if an assembly is already present or not, but I may be wrong.
     
  10. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    What I am trying to do is make code in a package OPTIONALLY use another package IF that package is installed rather than REQUIRING that other package.

    In other words, if Unity.Mathematics is installed, my package will expose methods that work with float2, if not it will fall back to methods that use Vector2.
     
  11. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,644
    Ah ok then from what I remember that option is what you are looking for. In your assembly you enable the define uf unity.mathematics is present. I think when I did my test months ago was actually for the same precise reason (optionally enable unity math if present) and it worked. If you can't figure it out I'll dig the example when I have time .
     
  12. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Well the conditional works just fine, but the problem is the package dependency. Unity essentially doesn't make the Mathematics assembly even visible to my package unless I add it as a dependency. At which point, isn't it now required rather than optional?
     
  13. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,644
    Hmm yes what you say makes sense , I'll do some tests to remember what I did
     
  14. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Would be most appreciated! Thanks :)
     
  15. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,644
    OK now I remember, that option is only to have different behaviours according the version of the package, but the package must be included. It's a shame, I see how it could be used like you say.

    Tagging @HaraldNielsen and @karl_jones who replied to me the first time on a similar question.
     
  16. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Hmm. Based on what @maximeb_unity said originally, it should be doing what we are wanting.
     
  17. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,644
  18. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    After reading that thread as well, I think I understand what is happening. Sort of. Some clarification would be nice.

    But what I think is happening here is you can declare that Package A has a Reference to Package B. If Package B is installed, great it can be used. If Package B is NOT installed, then the system will still try to compile Package A anyway and as long as it doesn't use code from Package B it should compile fine with no errors.

    This is where the Version Defines would work.

    However, the one piece I would like clarification on, is what is the difference from "Reference" and "Dependency" as far as asmdefs go. So the above system sounds like exactly what we are after. If a "referenced" package is installed, we can use it, just as long as we handle when it isn't installed. A "soft" dependency. But a "hard" dependency would be we MUST have this package, and I don't see where that is defined by the system. A large part of a package manager of course is managing those dependencies so if I install one package it also installs all the others that it NEEDS to have.

    Going to do a big more digging.
     
    Tuncle likes this.
  19. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Ahh nevermind I see it now. Makes perfect sense.

    What confused me was that I was focused in on the assembly definition and forgetting the package.json all together.

    Ok so in summary this is how it works. You have two things that factor in. The overall package's "package.json" file, and the Assembly Definition (asmdef file) for each assembly in your package.

    In the package.json is where top level information about package is contained along with hard dependencies. If MyPackage must have Mathematics installed to work, then it would be defined as a dependency here in the package.json

    In the Assembly Definition for a given assembly (eg runtime, or editor) is where you define what other assemblies your assembly references. These are soft references, in that if the reference is not found, Unity will still try to compile the assembly anyway. This is where you can also set up preprocessor defines to be set if an assembly reference is installed. This allows you to wrap the relevant code so that if the reference is not installed, it will still compile.
     
  20. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,644
    I see, so one should add the soft dependency anyway, regardless if is installed or not, so that the check can be done. Yes it makes sense.
     
  21. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    I'm glad to see you were able to figure it out. There are two different concepts that often get confused: a package and an assembly are not the same thing. A package is a container for assets and code; an assembly is a compiled code unit. Other package managers don't necessarily deal with this the same way - for example, Nuget automatically adds the References to your .csproj when you add a package dependency (but they are still separate concepts); npm has no concept of assembly at all, so there aren't two different concept in the first place.

    Adding a package as a dependency in package.json tells the Package Manager that in order to use your package, those other packages must also be present (presumably because you're referencing code from it without scripting symbols); on the other hand, adding a Reference to an Assembly Definition tells the Compiler to include that other assembly during compilation. Since a package can contain multiple assemblies (or even none), you need to explicitly tell the compiler which ones you want to use for which of your own assemblies. That is what References are for, and that's why it needs to be specified even for optional assembly references - those will simply be ignored by the compiler if the optional package dependency is not met.

    Hopefully this clarifies things a bit!
     
  22. as3mbus

    as3mbus

    Joined:
    Dec 5, 2016
    Posts:
    71
    sorry if this some kind of necro bumping. but i need to know if this applicable to an entire assembly folder not only a script.

    i have separated a logic from certain dependencies. now i have additional folder that i dont want to include if this Optional dependencies are not present. can i do that ? or i'm supposed to make another package that have hard dependencies to the base package and the dependency it needs.

    thank you :)
     
  23. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    Have you checked the Version Defines feature in Assembly Definitions? This turns on defines you decide based on the presence of other packages with specified versions. These defines can be used to disable whole asmdefs (see Define Constraints in the same manual page) or can be sprinkled through your code with
    #if
    statements. Watch out - that can easily become unmanageable if you abuse them.

    A separate package with hard dependencies is definitely a good option if these optional functionality are clearly separate from the main asmdef. It might end up being easier to debug and more decoupled, which helps with maintainability over time.
     
  24. as3mbus

    as3mbus

    Joined:
    Dec 5, 2016
    Posts:
    71
    thanks for the reply

    Looks like i missed define constraint while reading through it

    so does this means i can create version defines and apply those define in define constraint in a single asmdef?

    if that is, it could be a neat trick to have.

    but yeah separating package would make more sense but also more stuff for me to maintain. looks like i'm just getting lazy.

    the functionality in the code is separate. as i tried to implement humble object pattern. but it's more or less dependent to main asmdef to work

    it's like the relation of UnityEngine and UnityEngine.Ui

    but in this case it's `Package` and `Package.OptionalDependencies`

    to ensure clarity here's the package i am trying to extract

    https://github.com/as3mbus/A3-Audio-System/tree/master/Packages/AudioControl

    there are Unity folder which have this dependency to the root folder classes. and this folder require additional dependency in order to work

    is it a good idea to separate those into multiple package ?
     
    Last edited: Apr 8, 2020
  25. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    Presumably, yes. Version Defines only apply to the asmdef where they are defined, so that an asmdef can control how it turns on its functionality based on the optional dependencies being present without polluting the list of defines for all other assemblies.

    I can't really answer that one - it's up to you, whether you'd like people to explicitly add your second package to their project to enable its features, or if you prefer your package to appear as a single package, but then expect/direct your users to add the optional dependencies in order to turn on the added functionality (so, indirectly adding it). In general, the separate package approach is better as it provides looser coupling, smaller packages, finer upgradability options, and simpler automated testing setups. But it's up to you :)
     
  26. as3mbus

    as3mbus

    Joined:
    Dec 5, 2016
    Posts:
    71
    well it would be nice if 2018 could have an updated asmdef editor so i can do that. since i can't force my team to instantly upgrade to 2019 version of unity :(

    but yeah looser coupling looks nice. but i'm still in a bind for managing multiple UPM project inside a git repositories
     
  27. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    There's an easy workaround: using the project's Scripting Symbols in the Player Settings to manually "turn on" the optional parts of your package. In the most recent versions of 2018 LTS, asmdef references that are missing are ignored, so it's possible to still have optional dependencies - they just need to be turned on explicitly rather than automatically through the versionDefine property. Hope that helps!
     
  28. as3mbus

    as3mbus

    Joined:
    Dec 5, 2016
    Posts:
    71
    i see. but that will require me to add additional notes to readme in order to inform any of the package user. i'm just glad that version define exist. but not happy with it's limitation to 2019 and later. the best solution is just to upgrade to unity 2019.
     
  29. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    Do you know which version adds support for essentially optional references? I may need to bump up the minimum version of my plugin just for this :p (I currently support 2018.3+)
     
  30. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    I believe 2018.4.13 is the minimum version that no longer complains about missing asmdef References, allowing you to use optional dependencies from that version on (automatically turned on in 2019.1+, manually turned on by users in the 2018.4 releases).
     
    Michael-Ryan likes this.
  31. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    Where/how is this turned on manually?
     
  32. maximeb_unity

    maximeb_unity

    Unity Technologies

    Joined:
    Mar 20, 2018
    Posts:
    556
    Michael-Ryan likes this.
  33. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    Ah sorry, I just meant the optional reference part (not the version define)
    My use case is adding optional support for the new input system, so I can use the preprocessors it already defined by being active?
     
    KReguieg likes this.