On 13. 6. 25 01:14, Timofei Zhakov wrote:
(...cut...)

    Thanks for your explanation!

    I'd add a few points from myself.

    When a library is linked into another target through
    target_link_libraries(), it can be either PUBLIC, PRIVATE, or
    INTERFACE:

    - PRIVATE means that the dependency will be entirely used in the
    following target (both include directories and link flags are
    copied to the new target). For example, when APR is linked into
    libsvn_something as a PRIVATE dependency, this library gains
    access to APR functions and headers. However, it doesn't spread
    to the target depending on our libsvn_something (like our main
    svn.exe). Actually, there is an exception that copies link flags
    in a static build, but it's a different story. I mean it's not
    the main point.

    As for another, more real world example, libsvn_fs_fs is a
    completely internal library without any public APIs. I mean those
    used in our programs. They usually only link against let's say
    libsvn_fs (in the most abstract scenario). libsvn_fs does link
    libsvn_fs_fs, but doesn't use it in its public api. This all
    means that if it's linked as a PRIVATE dependency, no includes of
    libsvn_fs_fs will be available for libsvn_fs. (let's imagine they
    would be in different directories for clarity)

    Also, answering Branko's question, optimising include directories
    might be helpful to explicitly control whether the dependency is
    used or not. For example, our libsvn_diff doesn't use apr util.
    So if someone would call apr util api on accident, we will notice
    this because the build would no longer be passing.

    Yup. And libsvn_diff doesn't link apr-util, build.conf says so and
    all our generated target dependencies derive from that. However:

    trunk/subversion/libsvn_diff$  grep svn_utf.h *.c
    deprecated.c:#include "svn_utf.h"
    diff_file.c:#include "svn_utf.h"
    diff_memory.c:#include "svn_utf.h"
    parse-diff.c:#include "svn_utf.h"
    util.c:#include "svn_utf.h"


    So it needs -I/some/path/to/apr-util/include/apr-1 but it doesn't
    need libaprutil.so (or .a or .lib or .dylib etc.). This is exactly
    why I didn't want to change the dependency lists in build.conf.


    - INTERFACE linkage only affects the targets dependent on the
    library. It does literally nothing on the target itself, but
    spreads onto dependent libraries.

    - PUBLIC dependencies are a sort of combination of those both
    types. For example, apr is the best example of a PUBLIC
    dependency, because it is used in the library itself and required
    in the public header files (for example libsvn_client exports
    svn_client.h, which includes apr.h. Meaning that apr.h is a part
    of libsvn_client public api).

    Right now libsvn_subr has the following dependencies:

    target_link_libraries(libsvn_subr PRIVATE
        external-aprutil
        external-apr
        external-xml
        external-zlib
        external-sqlite
        external-intl
        external-lz4
        external-utf8proc
      )

    I think it should be like:

    target_link_libraries(libsvn_subr PUBLIC
        external-aprutil
        external-apr
      )
    target_link_libraries(libsvn_subr PRIVATE
        external-xml
        external-zlib
        external-sqlite
        external-intl
        external-lz4
        external-utf8proc
      )

    Initially, I thought that all dependencies are explicitly listed
    in the build.conf, so I didn't take the effort that time. Should
    I rework the generator to produce such targets?

    The link dependencies are in build.conf. The public/private
    distinction isn't (since that doesn't affect linking a target).
    The autotools build, based on build.conf, and also the generated
    Visual Studio files, make all include paths available to all
    targets. I'd have to double-check, but I think the exceptions to
    this rule are the (Swig) bindings, which get some extra help.


    This would be the cmake-ish way to fix this problem. And just an
    improvement.


    Well, I'd hate to add an explicit flag in build.conf just to
    distinguish between public and private dependencies. Having said
    that, we only have issues with external-aprutil (and, to some
    degree, external-apr, since they should be treated in the same
    way). So how about adding this knowledge directly into
    build/generator/gen_cmake.py? It is, after all, its job is to
    generate correct dependencies for cmake. It already adds the
    "external-" prefix to some of the library names; it may as well
    put apr and apr-util into the PUBLIC space.

    The attached patch appears to work for me.


+1, except for several minor notices.

1. What is the actual purpose of a frozenset PUBLIC_LIB_DEPENDS? I mean just above we are performing exactly the same check, but using an '[...]' construction and I think it's not worthed to optimise performance of a build script and we use it just once. So why not do this instead?:


Eh, that's just me, optimizing too soon. A linear lookup would be as fast as a hash lookup for two elements. Plus, there's a nice place at the top of the script for a comment.


@@ -170,9 +175,14 @@
               # TODO:
               pass
             else:
-              libs.append("external-" + dep.name <http://dep.name>)
+              dep_name = "external-" + dep.name <http://dep.name>
+              if (dep_name in ["external-apr", "external-aprutil"]
+                  and not isinstance(target, gen_base.TargetExe)):
+                public_libs.append(dep_name)
+              else:
+                private_libs.append(dep_name)
           else:
-            libs.append(dep.name <http://dep.name>)
+            private_libs.append(dep.name <http://dep.name>)
         elif isinstance(dep, gen_base.ObjectFile):
           for source in self.graph.get_sources(gen_base.DT_OBJECT, dep,
                                                gen_base.SourceFile):
2. It's maybe just an enhancement for the future, if we decide to, for example, export a cmake config, but it might be better to treat some libsvn dependencies as PUBLIC. For example, I'm sure most of our headers include something from libsvn_subr, so technically it's a public dependency for them. This most probably would not change anything since they have the same include directory, but still, in theory it could.

In that case, we could just add these to the existing list of always-public dependencies, right?

Anyway, go ahead and commit the patch with or without any changes.

-- Brane

Reply via email to