From c810e4104958dfa4ef16386d1e27f8ecdf9cae80 Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Tue, 28 May 2019 13:02:30 +0300 Subject: [PATCH] smarter install logic --- .github/cpt/Dockerfile | 15 ++ .github/cpt/entrypoint.sh | 25 ++ .github/main.workflow | 2 +- b2/install-extra.jam | 239 ++++++++++++++++++ conanfile.py | 8 +- exports/build.jam | 45 ++-- .../enumflags-config-version.cmake | 11 + exports/install-cmake/enumflags-config.cmake | 9 + exports/install-path.jam | 38 --- exports/install-pc/enum-flags.pc | 4 + jamroot.jam | 27 +- 11 files changed, 353 insertions(+), 70 deletions(-) create mode 100644 .github/cpt/Dockerfile create mode 100755 .github/cpt/entrypoint.sh create mode 100644 b2/install-extra.jam create mode 100644 exports/install-cmake/enumflags-config-version.cmake create mode 100644 exports/install-cmake/enumflags-config.cmake delete mode 100644 exports/install-path.jam create mode 100644 exports/install-pc/enum-flags.pc diff --git a/.github/cpt/Dockerfile b/.github/cpt/Dockerfile new file mode 100644 index 000000000..b098681dc --- /dev/null +++ b/.github/cpt/Dockerfile @@ -0,0 +1,15 @@ +FROM conanio/gcc8 AS base + +LABEL "com.github.actions.name"="conan-actions" +LABEL "com.github.actions.description"="GitHub Actions for building/publishing with Conan" +LABEL "description"="GitHub Actions for building/publishing with Conan" +LABEL "com.github.actions.icon"="package" +LABEL "com.github.actions.color"="blue" + +LABEL "repository"="http://github.com/grisumbras/conan-actions" +LABEL "homepage"="http://github.com/grisumbras/conan-actions" +LABEL "maintainer"="Dmitry Arkhipov " + +USER root +ADD entrypoint.sh /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] diff --git a/.github/cpt/entrypoint.sh b/.github/cpt/entrypoint.sh new file mode 100755 index 000000000..40df60d7f --- /dev/null +++ b/.github/cpt/entrypoint.sh @@ -0,0 +1,25 @@ +#!/bin/sh -l + + +eval "$(pyenv init -)" +eval "$(pyenv virtualenv-init -)" + + +# fixing issue with conan_package_tools and python_requires +if [ x != "x$CONAN_UPLOAD" ]; then + conan remote add upload_repo $CONAN_UPLOAD +fi + +i=1 +old_ifs=$IFS +IFS=, +for r in $CONAN_REMOTES; do + conan remote add env_remote_$i "$r" + i=$(($i+1)) +done +IFS=$old_ifs + + +conan remote list +conan search b2-helper -r upload_repo +python build.py diff --git a/.github/main.workflow b/.github/main.workflow index eba6ea107..42d41bac0 100644 --- a/.github/main.workflow +++ b/.github/main.workflow @@ -17,7 +17,7 @@ workflow "Build" { action "build" { needs = ["filter-not-publish", "store-env"] - uses = "grisumbras/conan-actions/cpt@master" + uses = "./.github/cpt" } diff --git a/b2/install-extra.jam b/b2/install-extra.jam new file mode 100644 index 000000000..1060dc6f2 --- /dev/null +++ b/b2/install-extra.jam @@ -0,0 +1,239 @@ +# Copyright 2019 Dmitry Arkhipov +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + +import feature ; +import param ; +import path ; +import project ; +import targets ; + + +.dirs + = exec-prefix bindir sbindir libexecdir datarootdir datadir + sysconfdir sharedstatedir localstatedir runstatedir includedir + oldincludedir docdir infodir htmldir dvidir pdfdir psdir libdir lispdir + localedir mandir + ; + + +# features that specify paths to installation prefixes and well-known +# installation directories +feature.feature stage-prefix : : free path ; +feature.feature install-prefix : : free path ; +for local dir in $(.dirs) { feature.feature install-$(dir) : : free ; } + +# feature that specifies the name of the package to which installed files +# belong +feature.feature install-package : : free ; + + + +class install-extra-target-class : install-target-class { + import install-extra ; + + # If is not set, sets it based on the project data. + rule update-location ( property-set ) { + local loc = [ $(property-set).get ] ; + if ! $(loc) { + # check if installation to a well-known directory was requested + local matches = [ MATCH "^\\((.+)\\)(.*)" : $(self.name:G=) ] ; + if $(matches) { + loc = [ well-known-location $(matches) : $(property-set) ] ; + } else { + loc = [ path.root $(self.name) [ $(self.project).get location ] ] ; + } + property-set = [ $(property-set).add-raw $(loc:G=) ] ; + } + return $(property-set) ; + } + + # Returns location inside a well-known directory + local rule well-known-location ( well-known-dir subdir : property-set ) { + # at this point subdir is either an empty string or an absolute path, but + # we need it to be either an empty string or a relative path + if $(subdir) != "" { subdir = [ path.relative $(subdir) / ] ; } + + local prefix + = [ install-extra.get-dir $(well-known-dir) + : $(property-set) + : staged + : [ $(self.project).get id ] + ] ; + return [ path.root $(subdir) $(prefix) ] ; + } +} + + +rule install ( name : sources * : requirements * : default-build * ) { + param.handle-named-params + sources requirements default-build usage-requirements ; + + local project = [ project.current ] ; + + # Unless the user has explicitly asked us to hardcode dll paths, add + # false in requirements, to override default value. + if ! true in $(requirements) { + requirements += false ; + } + + if in $(requirements:G) { + import errors ; + errors.user-error + The property is not allowed for the 'install' rule. ; + } + + targets.create-metatarget install-extra-target-class + : $(project) : $(name) : $(sources) : $(requirements) : $(default-build) ; +} + + +# Returns the path to the requested well-known directory +rule get-dir ( well-known-dir : property-set : flags * : project ? ) { + local package-name = [ get-package-name $(property-set) : $(project) ] ; + + local relative ; + if relative in $(flags) { relative = relative ; } + + local staged ; + if staged in $(flags) { staged = staged ; } + + return + [ get-dir-aux $(well-known-dir) + : $(package-name) + : $(property-set) + : $(relative) + : $(staged) + ] ; +} + + +rule get-package-name ( property-set : package ? ) { + if ! $(package) { + local project = [ project.current ] ; + package = [ $(project).get id ] ; + if ! $(package) { + local root = [ $(project).get project-root ] ; + root = [ path.root $(root) [ path.pwd ] ] ; + package = $(root) ; + } + } + return $(package:B) ; +} + + +rule target-native-path ( path : property-set ) { + local os ; + switch [ $(property-set).get ] { + case cygwin : os = CYGWIN ; + case vms : os = VMS ; + case windows : os = NT ; + case * : os = UNIX ; + } + local native = native-$(os) ; + + return [ path.$(native) $(path) ] ; +} + + +local rule get-dir-aux + ( well-known-dir : package-name : property-set : relative ? : staged ? ) +{ + local loc ; + # We treat the 'prefix' directory in a special way, because it doesn't have + # a base directory and it can be overriden by staging prefix. + if $(well-known-dir) = prefix { + loc + = [ get-install-prefix $(package-name) : $(property-set) : $(staged) ] ; + } else { + # First, try getting the path for requested directory from properties. + loc = [ $(property-set).get ] ; + + local info = [ well-known-default $(well-known-dir) : $(package-name) ] ; + # Otherwise, use the default path. In both cases, it could be a + # relative path. + loc ?= $(info[1]) ; + + # If there is a base directory, we may need to either prepend it to the + # result, if we want an absolute path, or remove it from the beginning, if + # we want a relative path. + if $(info[2]) { + local rooted = [ path.is-rooted $(loc) ] ; + + local operation ; + if $(rooted) && $(relative) { + # We only need to prepend base if the result is relative. + operation = relative ; + } else if ! ( $(rooted) || $(relative) ) { + # We only need to remove base if the result is absolute. + operation = root ; + } + + if $(operation) { + # Always get absolute path to base. + local base + = [ get-dir-aux $(info[2]) + : $(package-name) + : $(property-set) + : + : $(staged) + ] ; + loc = [ path.$(operation) $(loc) $(base) ] ; + } + } + } + + return $(loc) ; +} + + +# For a given well-known directory returns its base directory and +# relative path +local rule well-known-default ( well-known-dir : package-name ) { + switch $(well-known-dir) { + case exec-prefix : return "" prefix ; + case bindir : return bin exec-prefix ; + case sbindir : return sbin exec-prefix ; + case libexecdir : return libexec exec-prefix ; + case libdir : return lib exec-prefix ; + case datarootdir : return share prefix ; + case datadir : return "" datarootdir ; + case sysconfdir : return etc prefix ; + case sharedstatedir : return com prefix ; + case localstatedir : return var prefix ; + case runstatedir : return run localstatedir ; + case includedir : return "include" prefix ; + case oldincludedir : return /usr/include ; + case docdir : return $(package-name:D=doc) datarootdir ; + case infodir : return info datarootdir ; + case htmldir : return "" docdir ; + case dvidir : return "" docdir ; + case pdfdir : return "" docdir ; + case psdir : return "" docdir ; + case lispdir : return emacs/site-lisp datarootdir ; + case localedir : return locale datarootdir ; + case mandir : return man datarootdir ; + case * : + import errors ; + errors.error + $(well-known-dir) is not a well-known installation directory. Choose + one of prefix, "$(.dirs:J=, )". ; + } +} + + +local rule get-install-prefix ( package-name : property-set : staged ? ) { + local prefix ; + if $(staged) { prefix = [ $(property-set).get ] ; } + prefix ?= [ $(property-set).get ] ; + if ! $(prefix) { + if [ modules.peek : NT ] { + prefix = C:\\$(package-name) ; + } else { + return /usr/local ; + } + } + return $(prefix) ; +} diff --git a/conanfile.py b/conanfile.py index e0c854085..d5f58b42e 100644 --- a/conanfile.py +++ b/conanfile.py @@ -7,7 +7,7 @@ import re -b2 = python_requires("b2-helper/0.2.0@grisumbras/testing") +b2 = python_requires("b2-helper/0.3.0@grisumbras/testing") def get_version(): @@ -32,14 +32,18 @@ class EnumFlagsConan(b2.B2.Mixin, ConanFile): exports_sources = ( "jamroot.jam", "*build.jam", - "exports/*.jam", "*.hpp", "*.cpp", "LICENSE*", + "b2/*", ) no_copy_source = True build_requires = "boost_build/[>=1.68]@bincrafters/stable" + def b2_setup_builder(self, builder): + builder.properties.install_prefix = self.package_folder + return builder + def package_info(self): self.info.header_only() diff --git a/exports/build.jam b/exports/build.jam index 29d09eacb..abc91be0f 100644 --- a/exports/build.jam +++ b/exports/build.jam @@ -1,41 +1,54 @@ -import install-path ; import make ; +import path ; import print ; +import property-set ; +import feature ; - -prefix = [ install-path.prefix enum-flags ] ; -execprefix = [ install-path.exec-prefix $(prefix) ] ; -libdir = [ install-path.libdir $(execprefix) ] ; -includedir = [ install-path.includedir $(prefix) ] ; +import b2/install-extra : install ; make enum-flags.pc : : @write-pc ; -install install-pc : enum-flags.pc : $(libdir)/pkgconfig ; +local install-pc = [ install (libdir)/pkgconfig : enum-flags.pc ] ; make enumflags-config.cmake : : @write-cmake-config ; make enumflags-config-version.cmake : : @write-cmake-version ; -install install-cmake - : enumflags-config.cmake - enumflags-config-version.cmake - : $(libdir)/cmake/enumflags-$(VERSION) - ; +local install-cmake + = [ install (libdir)/cmake/enumflags-$(VERSION) + : enumflags-config.cmake + enumflags-config-version.cmake + ] ; -alias install : install-pc install-cmake ; -explicit install install-pc install-cmake ; +alias install : $(install-pc) $(install-cmake) ; +explicit install ; rule write-pc ( target : sources * : properties * ) { + local ps = [ property-set.create $(properties) ] ; + + local prefix = [ install-extra.get-dir prefix : $(ps) ] ; + prefix = [ install-extra.target-native-path $(prefix) : $(ps) ] ; + + local includedir = [ install-extra.get-dir includedir : $(ps) : relative ] ; + includedir = [ path.root $(includedir) "${prefix}" ] ; + includedir = [ install-extra.target-native-path $(includedir) : $(ps) ] ; + write $(target) - : "Name: enum-flags" + : "prefix=$(prefix)" + "includedir=$(includedir)" + "" + "Name: enum-flags" "Description: Bit-flags for C++ scoped enums" "Version: $(VERSION)" - "Cflags: -I$(includedir)" + "Cflags: -I${includedir}" "" ; } rule write-cmake-config ( target : sources * : properties * ) { + local ps = [ property-set.create $(properties) ] ; + local includedir = [ install-extra.get-dir includedir : $(ps) ] ; + write $(target) : "if(TARGET EnumFlags::EnumFlags)" " return()" diff --git a/exports/install-cmake/enumflags-config-version.cmake b/exports/install-cmake/enumflags-config-version.cmake new file mode 100644 index 000000000..439fea2b0 --- /dev/null +++ b/exports/install-cmake/enumflags-config-version.cmake @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION 0.1.0) + +if(NOT PACKAGE_FIND_VERSION OR PACKAGE_FIND_VERSION EQUAL 0.1.0) + set(PACKAGE_VERSION_EXACT TRUE) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + set(PACKAGE_VERSION_UNSUITABLE FALSE) +else() + set(PACKAGE_VERSION_EXACT FALSE) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/exports/install-cmake/enumflags-config.cmake b/exports/install-cmake/enumflags-config.cmake new file mode 100644 index 000000000..8c20485ed --- /dev/null +++ b/exports/install-cmake/enumflags-config.cmake @@ -0,0 +1,9 @@ +if(TARGET EnumFlags::EnumFlags) + return() +endif() + +add_library(EnumFlags::EnumFlags INTERFACE IMPORTED) +set_target_properties( + EnumFlags::EnumFlags + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "/home/arhipov_d/dev/1/enum-flags/tmp/stage/include" +) diff --git a/exports/install-path.jam b/exports/install-path.jam deleted file mode 100644 index 084e64909..000000000 --- a/exports/install-path.jam +++ /dev/null @@ -1,38 +0,0 @@ -import modules ; -import option ; -import property ; - - -rule prefix ( package-name : requirements * ) { - local prefix - = [ option.get prefix - : [ property.select : $(requirements) ] - ] ; - prefix = $(prefix:G=) ; - requirements - = [ property.change $(requirements) : ] ; - - if ! $(prefix) { - if [ modules.peek : NT ] { - prefix = C:\\$(package-name) ; - } else if [ modules.peek : UNIX ] { - prefix = /usr/local ; - } - } - return $(prefix) ; -} - - -rule exec-prefix ( prefix ) { - return [ option.get execprefix : $(prefix) ] ; -} - - -rule libdir ( execprefix ) { - return [ option.get libdir : $(execprefix)/lib ] ; -} - - -rule includedir ( prefix ) { - return [ option.get includedir : $(prefix)/include ] ; -} diff --git a/exports/install-pc/enum-flags.pc b/exports/install-pc/enum-flags.pc new file mode 100644 index 000000000..a4d587abf --- /dev/null +++ b/exports/install-pc/enum-flags.pc @@ -0,0 +1,4 @@ +Name: enum-flags +Description: Bit-flags for C++ scoped enums +Version: 0.1.0 +Cflags: -I/home/arhipov_d/dev/1/enum-flags/tmp/stage/include diff --git a/jamroot.jam b/jamroot.jam index 1d5bfedb6..4e9cbb918 100644 --- a/jamroot.jam +++ b/jamroot.jam @@ -1,24 +1,25 @@ -import package ; -import path ; +import modules ; +import b2/install-extra : install ; project enum-flags ; + constant VERSION : 0.1.0 ; alias libs : usage-requirements include ; -package.install headers enum-flags - : include - : - : - : [ path.glob-tree include : *.hpp ] - ; -explicit headers ; - -package.install-data license : enum-flags : LICENSE ; +local headers + = [ install (includedir) + : [ glob-tree-ex include : *.hpp ] + : include + ] ; -alias install : headers license exports//install ; -explicit install headers license ; +alias install + : exports//install + $(headers) + [ install (docdir) : LICENSE ] + ; +explicit install ;