diff --git a/check/Makefile.am b/check/Makefile.am index 68c6d84312941a13277554b342e818b558aed563..618a90ad004e1da257acc5437701f29f704b73e0 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 0000000000000000000000000000000000000000..544f1d35c94e943258a99e6cf4bf5b7c4b7081f3 --- /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 0000000000000000000000000000000000000000..0cfbdfdaeea68b93f7bab775389d235c62be9feb --- /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 cfebdba1ad538337246c1d57b5de6e053c433b7f..1ca3347da27be42f78dab40eebf484f3cb46e011 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_libs_private(); + enable_cflags_private(); + } else - disable_private_libs(); + { + disable_libs_private(); + 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 6e9907c2a7562eb28ebe972a2773da00076ec0c6..75e016e1dddc3f1da059a36cba16589478200c3d 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,14 +850,103 @@ 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); } +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) { @@ -906,8 +964,8 @@ 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, gboolean ignore_libs_private, + gboolean ignore_requires_private, gboolean ignore_cflags_private) { char *str; char *p; @@ -964,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) @@ -972,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) @@ -1088,8 +1152,9 @@ 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_requires_private) + gboolean ignore_libs_private, + gboolean ignore_requires_private, + gboolean ignore_cflags_private) { FILE *f; Package *pkg; @@ -1133,8 +1198,8 @@ 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); + 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 db1bf8629e85e0d940b377f9b9e7d156a917197d..93a3f95ccd7a14ac6409c227edbd3ceac25114e8 100644 --- a/parse.h +++ b/parse.h @@ -24,8 +24,9 @@ Package *parse_package_file (const char *key, const char *path, gboolean ignore_requires, - gboolean ignore_private_libs, - gboolean ignore_requires_private); + gboolean ignore_libs_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 c666fe5d69297252dea9e58431ca3d2373539fa3..79335ff46f14303599604dff5bd1dc372681f080 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 a147fc815a41bb84eb9d3f10a8ede57b792a0a31..8272d1532e0c4daf994f4d870cbbcc60b38f55af 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 4c1523aaa8d444cf4c2005437768203bd9da84d4..193b5f950f69a0a1e417b201b9d9fe96608384af 100644 --- a/pkg.c +++ b/pkg.c @@ -49,7 +49,8 @@ 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 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_libs_private, ignore_requires_private, + ignore_cflags_private); g_free (key); if (pkg != NULL && strstr (location, "uninstalled.pc")) @@ -950,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); @@ -958,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); @@ -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 @@ -1212,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 @@ -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 c6732bdf3aa15bf6e0a989d32e1b8553cfe951f9..cc08e50e126bfd1781a7c90fee9c6d5c30893112 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 */ }; @@ -116,12 +117,14 @@ 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); 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;