From 481ef5b7436ffd8b55ce2d017e88a49aba5bb772 Mon Sep 17 00:00:00 2001 From: Oneric Date: Tue, 21 Sep 2021 18:37:16 +0200 Subject: [PATCH 1/3] parse: split out _do_parse_cflags Pure refactoring with no functional changes, prepares addition of Cflags.private. --- parse.c | 73 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/parse.c b/parse.c index 6e9907c..f4a1baa 100644 --- a/parse.c +++ b/parse.c @@ -798,40 +798,9 @@ parse_libs_private (Package *pkg, const char *str, const char *path) } static void -parse_cflags (Package *pkg, const char *str, const char *path) +_do_parse_cflags (Package *pkg, int argc, char **argv) { - /* Strip out -I flags, put them in a separate list. */ - - char *trimmed; - char **argv = NULL; - int argc = 0; - GError *error = NULL; int i; - - if (pkg->cflags) - { - verbose_error ("Cflags field occurs twice in '%s'\n", path); - if (parse_strict) - exit (1); - else - return; - } - - trimmed = trim_and_sub (pkg, str, path); - - if (trimmed && *trimmed && - !g_shell_parse_argv (trimmed, &argc, &argv, &error)) - { - verbose_error ("Couldn't parse Cflags field into an argument vector: %s\n", - error ? error->message : "unknown"); - if (parse_strict) - exit (1); - else - { - g_free (trimmed); - return; - } - } i = 0; while (i < argc) @@ -881,9 +850,47 @@ parse_cflags (Package *pkg, const char *str, const char *path) g_free (flag); g_free (arg); - + ++i; } +} + +static void +parse_cflags (Package *pkg, const char *str, const char *path) +{ + /* Strip out -I flags, put them in a separate list. */ + + char *trimmed; + char **argv = NULL; + int argc = 0; + GError *error = NULL; + + if (pkg->cflags) + { + verbose_error ("Cflags field occurs twice in '%s'\n", path); + if (parse_strict) + exit (1); + else + return; + } + + trimmed = trim_and_sub (pkg, str, path); + + if (trimmed && *trimmed && + !g_shell_parse_argv (trimmed, &argc, &argv, &error)) + { + verbose_error ("Couldn't parse Cflags field into an argument vector: %s\n", + error ? error->message : "unknown"); + if (parse_strict) + exit (1); + else + { + g_free (trimmed); + return; + } + } + + _do_parse_cflags(pkg, argc, argv); g_strfreev (argv); g_free (trimmed); -- GitLab From bb8f1b7b914170f2e35c83023d4d04af25a59780 Mon Sep 17 00:00:00 2001 From: Oneric Date: Tue, 21 Sep 2021 19:45:25 +0200 Subject: [PATCH 2/3] Add Cflags.private field Those Cflags will be added if linking statically against a library; this is necessary if the public headers need to be mutated depending on linkage mode. Eg on Microsoft Windows varaibles whose definition resides in a shared library need to be declared with a special attribute; if linked to statically this attribute must not be used. With Cflags.private their headers can eg check if 'LIBRARYNAME_STATIC' is not defined to know that the special attribute is needed; without it everyone linking against the library will need to manually research what the expected macro is and set it depending on linkage mode. This field is also supported by pkgconf since version 0.9.3 and already used by (some) affected libraries targeting Microsoft Windows. Note that _do_parse_cflags always adds the flags to pkg->cflags and there is no pkg->cflags_private; instead the call to parse_cflags_private is conditional. This matches the existing implementation of Libs.private. Closes: https://gitlab.freedesktop.org/pkg-config/pkg-config/-/issues/38 --- check/Makefile.am | 2 ++ check/check-cflags-private | 11 +++++++ check/private-cflags.pc | 7 +++++ main.c | 10 ++++-- parse.c | 64 ++++++++++++++++++++++++++++++++++++-- parse.h | 3 +- pkg-config-guide.html | 18 ++++++++--- pkg-config.1 | 8 +++++ pkg.c | 17 +++++++++- pkg.h | 3 ++ 10 files changed, 131 insertions(+), 12 deletions(-) create mode 100755 check/check-cflags-private create mode 100644 check/private-cflags.pc diff --git a/check/Makefile.am b/check/Makefile.am index 68c6d84..618a90a 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -2,6 +2,7 @@ TESTS_ENVIRONMENT = PKG_CONFIG='$(TESTS_PKG_CONFIG)' $(TESTS_SHELL) TESTS = \ check-cflags \ + check-cflags-private \ check-libs \ check-mixed-flags \ check-non-l-flags \ @@ -40,6 +41,7 @@ EXTRA_DIST = \ requires-test.pc \ public-dep.pc \ private-dep.pc \ + private-cflags.pc \ includedir.pc \ missing-requires-private.pc \ missing-requires.pc \ diff --git a/check/check-cflags-private b/check/check-cflags-private new file mode 100755 index 0000000..544f1d3 --- /dev/null +++ b/check/check-cflags-private @@ -0,0 +1,11 @@ +#! /bin/sh + +set -e + +. ${srcdir}/common + +RESULT="-I/dummy/include" +run_test --cflags private-cflags + +RESULT="-DDUMMY_STATIC=1 $RESULT" +run_test --static --cflags private-cflags diff --git a/check/private-cflags.pc b/check/private-cflags.pc new file mode 100644 index 0000000..0cfbdfd --- /dev/null +++ b/check/private-cflags.pc @@ -0,0 +1,7 @@ +Name: Requires test package +Description: Dummy pkgconfig test package for testing Cflags/Cflags.private +Version: 1.0.0 +Libs: -L/dummy/lib -ldummy +Cflags: -I/dummy/include +Cflags.private: -DDUMMY_STATIC=1 + diff --git a/main.c b/main.c index cfebdba..7bc560e 100644 --- a/main.c +++ b/main.c @@ -615,9 +615,15 @@ main (int argc, char **argv) debug_spew ("Error printing disabled\n"); if (want_static_lib_list) - enable_private_libs(); + { + enable_private_libs(); + enable_cflags_private(); + } else - disable_private_libs(); + { + disable_private_libs(); + disable_cflags_private(); + } /* honor Requires.private if any Cflags are requested or any static * libs are requested */ diff --git a/parse.c b/parse.c index f4a1baa..39a63cd 100644 --- a/parse.c +++ b/parse.c @@ -896,6 +896,57 @@ parse_cflags (Package *pkg, const char *str, const char *path) g_free (trimmed); } +static void +parse_cflags_private (Package *pkg, const char *str, const char *path) +{ + /* + List of private Cflags. Private Cflags are flags which + are needed in the case of static linking. This can be required for + example on platforms which require special attributes to be set + for variables or functions which are defined in a shared library, + as is the case for Microsoft Windows. Affected libraries will need + to have ifdefs in their public headers to change the attributes + depending on whether they are being linked to staticly or dynamicly. + */ + + char *trimmed; + char **argv = NULL; + int argc = 0; + GError *error = NULL; + + if (pkg->cflags_private_num) + { + verbose_error ("Cflags.private field occurs twice in '%s'\n", path); + if (parse_strict) + exit (1); + else + return; + } + + trimmed = trim_and_sub (pkg, str, path); + + if (trimmed && *trimmed && + !g_shell_parse_argv (trimmed, &argc, &argv, &error)) + { + verbose_error ("Couldn't parse Cflags.private field into an argument vector: %s\n", + error ? error->message : "unknown"); + if (parse_strict) + exit (1); + else + { + g_free (trimmed); + return; + } + } + + _do_parse_cflags(pkg, argc, argv); + + g_strfreev (argv); + g_free (trimmed); + pkg->cflags_private_num++; + +} + static void parse_url (Package *pkg, const char *str, const char *path) { @@ -914,7 +965,7 @@ parse_url (Package *pkg, const char *str, const char *path) static void parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean ignore_requires, gboolean ignore_private_libs, - gboolean ignore_requires_private) + gboolean ignore_requires_private, gboolean ignore_cflags_private) { char *str; char *p; @@ -979,6 +1030,12 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, else if (strcmp (tag, "Cflags") == 0 || strcmp (tag, "CFlags") == 0) parse_cflags (pkg, p, path); + else if (strcmp (tag, "Cflags.private") == 0 || + strcmp (tag, "CFlags.private") == 0) + { + if (!ignore_cflags_private) + parse_cflags_private (pkg, p, path); + } else if (strcmp (tag, "Conflicts") == 0) parse_conflicts (pkg, p, path); else if (strcmp (tag, "URL") == 0) @@ -1096,7 +1153,8 @@ Package* parse_package_file (const char *key, const char *path, gboolean ignore_requires, gboolean ignore_private_libs, - gboolean ignore_requires_private) + gboolean ignore_requires_private, + gboolean ignore_cflags_private) { FILE *f; Package *pkg; @@ -1141,7 +1199,7 @@ parse_package_file (const char *key, const char *path, one_line = TRUE; parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs, - ignore_requires_private); + ignore_requires_private, ignore_cflags_private); g_string_truncate (str, 0); } diff --git a/parse.h b/parse.h index db1bf86..6135a4e 100644 --- a/parse.h +++ b/parse.h @@ -25,7 +25,8 @@ Package *parse_package_file (const char *key, const char *path, gboolean ignore_requires, gboolean ignore_private_libs, - gboolean ignore_requires_private); + gboolean ignore_requires_private, + gboolean ignore_cflags_private); GList *parse_module_list (Package *pkg, const char *str, const char *path); diff --git a/pkg-config-guide.html b/pkg-config-guide.html index c666fe5..79335ff 100644 --- a/pkg-config-guide.html +++ b/pkg-config-guide.html @@ -137,6 +137,13 @@ Libs: -L${libdir} -lfoo libraries support pkg-config, they should be added to Requires or Requires.private. +
  • Cflags.private: The compiler flags specific to the static version + of your package. This may be required if your public headers need to change + according to linkage mode, as is for example the case on Microsoft Windows + if a library exposes a variable. + Don't add any flags for required packages supporting pkg-config; + pkg-config will add those automatically.
  • +
  • Libs: The link flags specific to this package and any required libraries that don't support pkg-config. The same rule as Cflags applies here.
  • @@ -186,8 +193,9 @@ includedir=${prefix}/include Cflags: -I${includedir}/foo

    The most important pkg-config metadata fields are - Requires, Requires.private, Cflags, Libs - and Libs.private. They will define the metadata used by external + Requires, Requires.private, Cflags, Cflags.private + Libs and Libs.private. + They will define the metadata used by external projects to compile and link with the library.

    Requires and Requires.private define other modules @@ -214,9 +222,9 @@ Cflags: -I${includedir}/foo additional direct dependency.

    Finally, the Cflags contains the compiler flags for using the - library. Unlike the Libs field, there is not a private variant of - Cflags. This is because the data types and macro definitions are - needed regardless of the linking scenario.

    + library. Cflags.private contain compiler flags specific to only the + static version of the library; they will be used in addition to the regular + Cflags if --static is set.

    Using pkg-config files

    diff --git a/pkg-config.1 b/pkg-config.1 index a147fc8..8272d15 100644 --- a/pkg-config.1 +++ b/pkg-config.1 @@ -629,6 +629,14 @@ installed. This line should list the compile flags specific to your package. Don't add any flags for required packages; \fIpkg-config\fP will add those automatically. +.TP +.I "Cflags.private:" +This line should list the compile flags specific to the static version +of your package. This may be required if your public headers need to change +according to linkage mode, as is for example the case on Microsoft Windows +if a library exposes a variable. +Don't add any flags for required packages; \fIpkg-config\fP will +add those automatically. .\" .SH AUTHOR diff --git a/pkg.c b/pkg.c index 4c1523a..202c944 100644 --- a/pkg.c +++ b/pkg.c @@ -50,6 +50,7 @@ gboolean disable_uninstalled = FALSE; gboolean ignore_requires = FALSE; gboolean ignore_requires_private = TRUE; gboolean ignore_private_libs = TRUE; +gboolean ignore_cflags_private = TRUE; void add_search_dir (const char *path) @@ -300,7 +301,8 @@ internal_get_package (const char *name, gboolean warn) debug_spew ("Reading '%s' from file '%s'\n", name, location); pkg = parse_package_file (key, location, ignore_requires, - ignore_private_libs, ignore_requires_private); + ignore_private_libs, ignore_requires_private, + ignore_cflags_private); g_free (key); if (pkg != NULL && strstr (location, "uninstalled.pc")) @@ -1181,6 +1183,7 @@ print_package_list (void) ignore_requires = TRUE; ignore_requires_private = TRUE; + ignore_cflags_private = TRUE; /* Add the packages to a pointer array and sort by pkg->key first, to give * deterministic output. While doing that, work out the maximum key length @@ -1246,3 +1249,15 @@ disable_requires_private(void) { ignore_requires_private = TRUE; } + +void +enable_cflags_private(void) +{ + ignore_cflags_private = FALSE; +} + +void +disable_cflags_private(void) +{ + ignore_cflags_private = TRUE; +} diff --git a/pkg.h b/pkg.h index c6732bd..09dd255 100644 --- a/pkg.h +++ b/pkg.h @@ -84,6 +84,7 @@ struct Package_ int path_position; /* used to order packages by position in path of their .pc file, lower number means earlier in path */ int libs_num; /* Number of times the "Libs" header has been seen */ int libs_private_num; /* Number of times the "Libs.private" header has been seen */ + int cflags_private_num; /* Number of times the "Cflags.private" header has been seen */ char *orig_prefix; /* original prefix value before redefinition */ }; @@ -122,6 +123,8 @@ void enable_requires(void); void disable_requires(void); void enable_requires_private(void); void disable_requires_private(void); +void enable_cflags_private(void); +void disable_cflags_private(void); /* If TRUE, do not automatically prefer uninstalled versions */ extern gboolean disable_uninstalled; -- GitLab From 5bdb4d3a1ff0efb8a723a50a7c41795fbb3d61c8 Mon Sep 17 00:00:00 2001 From: Oneric Date: Thu, 30 Sep 2021 19:05:59 +0200 Subject: [PATCH 3/3] refactor: rename *_private_libs to *_libs_private This brings the function and variable names in line with parse_libs_private and the names used for the variables and functions of the Requires.privat and Cflags.private fields. --- main.c | 4 ++-- parse.c | 8 ++++---- parse.h | 2 +- pkg.c | 16 ++++++++-------- pkg.h | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/main.c b/main.c index 7bc560e..1ca3347 100644 --- a/main.c +++ b/main.c @@ -616,12 +616,12 @@ main (int argc, char **argv) if (want_static_lib_list) { - enable_private_libs(); + enable_libs_private(); enable_cflags_private(); } else { - disable_private_libs(); + disable_libs_private(); disable_cflags_private(); } diff --git a/parse.c b/parse.c index 39a63cd..75e016e 100644 --- a/parse.c +++ b/parse.c @@ -964,7 +964,7 @@ parse_url (Package *pkg, const char *str, const char *path) static void parse_line (Package *pkg, const char *untrimmed, const char *path, - gboolean ignore_requires, gboolean ignore_private_libs, + gboolean ignore_requires, gboolean ignore_libs_private, gboolean ignore_requires_private, gboolean ignore_cflags_private) { char *str; @@ -1022,7 +1022,7 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, } else if (strcmp (tag, "Libs.private") == 0) { - if (!ignore_private_libs) + if (!ignore_libs_private) parse_libs_private (pkg, p, path); } else if (strcmp (tag, "Libs") == 0) @@ -1152,7 +1152,7 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, Package* parse_package_file (const char *key, const char *path, gboolean ignore_requires, - gboolean ignore_private_libs, + gboolean ignore_libs_private, gboolean ignore_requires_private, gboolean ignore_cflags_private) { @@ -1198,7 +1198,7 @@ parse_package_file (const char *key, const char *path, { one_line = TRUE; - parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs, + parse_line (pkg, str->str, path, ignore_requires, ignore_libs_private, ignore_requires_private, ignore_cflags_private); g_string_truncate (str, 0); diff --git a/parse.h b/parse.h index 6135a4e..93a3f95 100644 --- a/parse.h +++ b/parse.h @@ -24,7 +24,7 @@ Package *parse_package_file (const char *key, const char *path, gboolean ignore_requires, - gboolean ignore_private_libs, + gboolean ignore_libs_private, gboolean ignore_requires_private, gboolean ignore_cflags_private); diff --git a/pkg.c b/pkg.c index 202c944..193b5f9 100644 --- a/pkg.c +++ b/pkg.c @@ -49,7 +49,7 @@ static GList *search_dirs = NULL; gboolean disable_uninstalled = FALSE; gboolean ignore_requires = FALSE; gboolean ignore_requires_private = TRUE; -gboolean ignore_private_libs = TRUE; +gboolean ignore_libs_private = TRUE; gboolean ignore_cflags_private = TRUE; void @@ -301,7 +301,7 @@ internal_get_package (const char *name, gboolean warn) debug_spew ("Reading '%s' from file '%s'\n", name, location); pkg = parse_package_file (key, location, ignore_requires, - ignore_private_libs, ignore_requires_private, + ignore_libs_private, ignore_requires_private, ignore_cflags_private); g_free (key); @@ -952,7 +952,7 @@ packages_get_flags (GList *pkgs, FlagType flags) } if (flags & LIBS_L) { - cur = get_multi_merged (pkgs, LIBS_L, TRUE, !ignore_private_libs); + cur = get_multi_merged (pkgs, LIBS_L, TRUE, !ignore_libs_private); debug_spew ("adding LIBS_L string \"%s\"\n", cur); g_string_append (str, cur); g_free (cur); @@ -960,7 +960,7 @@ packages_get_flags (GList *pkgs, FlagType flags) if (flags & (LIBS_OTHER | LIBS_l)) { cur = get_multi_merged (pkgs, flags & (LIBS_OTHER | LIBS_l), FALSE, - !ignore_private_libs); + !ignore_libs_private); debug_spew ("adding LIBS_OTHER | LIBS_l string \"%s\"\n", cur); g_string_append (str, cur); g_free (cur); @@ -1215,15 +1215,15 @@ print_package_list (void) } void -enable_private_libs(void) +enable_libs_private(void) { - ignore_private_libs = FALSE; + ignore_libs_private = FALSE; } void -disable_private_libs(void) +disable_libs_private(void) { - ignore_private_libs = TRUE; + ignore_libs_private = TRUE; } void diff --git a/pkg.h b/pkg.h index 09dd255..cc08e50 100644 --- a/pkg.h +++ b/pkg.h @@ -117,8 +117,8 @@ void verbose_error (const char *format, ...); gboolean name_ends_in_uninstalled (const char *str); -void enable_private_libs(void); -void disable_private_libs(void); +void enable_libs_private(void); +void disable_libs_private(void); void enable_requires(void); void disable_requires(void); void enable_requires_private(void); -- GitLab