Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

classes/cmake: MSYS2 Windows support #32

Merged
merged 11 commits into from
Dec 13, 2020

Conversation

mahaase
Copy link
Contributor

@mahaase mahaase commented Aug 7, 2020

generally we could remove the dependency to the make-class, by using the cmake --build and cmake --install functionality also for linux. (but we would loose the DESTDIR feature, so we have to check --prefix and CMAKE_PREFIX_PATH stuff for linux)

feedback welcome!

Copy link
Member

@jkloetzke jkloetzke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had a quick glance over the changes.

I think we should first define what the AUTOCONF_ values are for the MSYS and Windows. They are the central information for all recipes and classes to judge on what platform is compiled (AUTOCONF_BUILD) and for which platform the executables/libraries are generated (AUTOCONF_HOST) (see autoconf documentation).

Quickly googling around lead me to *-*-mingw32 for native gcc builds and clang seems to use something like *-win32 for windows. It would be really good to enumerate the target triples. I think the CMake should make the decision about the "generator" based on this information. This decouples the toolchain and CMake class. Other build systems will face similar challenges so it makes sense to have a looser coupling between toolchain and cmake class.

Did you come up with *-pc-msys in plugins/multiarch.pyby yourself or is this already a standard somewhere?

Comment on lines 26 to 28
if [[ ${CMAKE_TOOLCHAIN_FILE:+true} ]] ; then
CMAKE_TOOLCHAIN_FILE="${BOB_TOOL_PATHS[target-toolchain]}/${CMAKE_TOOLCHAIN_FILE}"
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather not re-introduce this historic mistake. The toolchain itself should not bother about the build systems used downstream. If CMake needs a toolchain file then this should be handled by the CMake class. That's the same as for the meson class that also needs something similar.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Understand, I'll fix this.

buildScript: |
# Make sure CMake finds other stuff by its own logic too
CMAKE_FIND_ROOT_PATH=
for i in "${@:2}" ; do
# CMake needs win paths if we are in MSYS2
[[ "$BOB_HOST_PLATFORM" == "msys" ]] && i="$(cygpath -m $i)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, isn't that more dependent on the target platform / toolchain? It should still be possible to compile for msys2/mingw23/mingw64 which do not take windows paths I suppose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, correct, it doesn't depend directly on MSYS. It's the combination of MSYS and Windows. I have to use the CMAKE_GENERATOR variable. If we use Visual Studio, we are sure, that we are on Windows system. I guess the unix paths should work, if we build e.g. with Unix Makefiles generator.

Comment on lines 42 to 44
BUILD_SHARED_LIBS=ON
else
BUILD_SHARED_LIBS=OFF
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why you removed this? The rationale is that all natively built libraries should be static because they are presumably used for host tools.

Copy link
Contributor Author

@mahaase mahaase Aug 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I missed here, is that the user can set the type manually inside the recipe.
making a library static or shared should not be limited by the system.
We need a mechanism to overwrite this. I'll add the handling, that ur defaults will be used, if the user havn't set this manually.

Comment on lines 14 to 20
# Install shared libraries only when cross compiling. On host builds only
# static libraries are installed.
if [[ "${AUTOCONF_BUILD:-unknown}" != "${AUTOCONF_HOST:-${AUTOCONF_BUILD:-unknown}}" ]]; then
INSTALL_SHARED=yes
fi

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This basically breaks the whole basement Linux build. For host builds no shared libraries must be used because they lead to tools that cannot be executed at all or not reliably.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check how to merge, that the user could overwrite the library type.

@@ -94,10 +88,10 @@ packageScript: |
{
installCopy "$@" /usr/ "/usr/include/***" \
/usr/lib/ \
"/usr/lib/*.a" \
${INSTALL_SHARED:+"/usr/lib/*.so*"} \
"/usr/lib/***" \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you install shared libraries even if they must not be installed.

"/usr/lib/pkgconfig/***" \
"/usr/lib/cmake/***" \
/usr/bin/ "/usr/bin/***" \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why include /bin for -dev packages?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmake will add the lib and the dll in the -config.cmake file automatically. so if the dll is not there, this will break the build.

Comment on lines 114 to 115
/usr/lib/ "/usr/lib/*.so*" \
/usr/bin/ "/usr/bin/*.dll" "/usr/bin/*.pdb" \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

installPackageLib should only install shared libraries. By removing *.so.* versioned libraries are broken.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no idea, why i changed this lines handling so linux library files, doesn't depends to the windows cmake stuff. xD. I will revert this.

Comment on lines 123 to 125
installCopy "$@" /usr/ \
/usr/bin/ "/usr/bin/***" \
"!*"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason to change this? Now the function does not install anything except binaries. This will miss e.g. plugins, configuration files, ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to re-check this.

Comment on lines 81 to 88
win64:
buildVars: [PKG_VERSION]
buildScript: |
mkdir -p install/usr
rsync -aH --exclude 'doc/' --exclude 'man/' "$1/cmake-${PKG_VERSION}-win64-x64/" install/usr/

packageScript: |
cp -a $1/install/* .
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should put this all into a separate recipes/devel/cmake-win64.yaml recipe. The windows CMake recipe has nothing in common with the regular one except the name 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just liked, that this was possible in this way. :D
But of course, creating a new recipe would have some advantages.
e.g. we can leave the BOB_HOST_PLATFORM stuff away.
I'll fix this.

else
# windows does not support a sigle build type, we have to select the
# current type with cmake --build . --config
OPTIONS+=( -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-RelWithDebInfo} )
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I'll investigate again, I guess, I also could set the BUILD_TYPE to bob for Windows, if I added this configuration to CMAKE_CONFIGURATION_TYPES.

${INSTALL_OPTIONS:+"${INSTALL_OPTIONS[@]}"}
else
makeParallel $MAKE_TARGET ${MAKE_OPTIONS:+"${MAKE_OPTIONS[@]}"}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do u think, could we use the cmake --build also for linux? In the end, cmake will call make also.

# will be built again...
cmake --build . --parallel "${MAKE_JOBS-$(nproc)}" \
--config ${CMAKE_BUILD_TYPE:-RelWithDebInfo} \
--target $INSTALL_TARGET \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a customizable install target? Will this ever used?
The cmake --install will call the default install target (cmake_install.cmake).

fi
else
make $INSTALL_TARGET \
DESTDIR=$DESTDIR \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will check, if that will change anything in Linux, if we use cmakes install_prefix instead of the DESTDIR of make.

@daxcore
Copy link
Contributor

daxcore commented Aug 9, 2020

yeah, we have to enumerate the triplets, here is how git for windows project is doing it: git-for-windows/msys2-runtime@6210daa

@mahaase
Copy link
Contributor Author

mahaase commented Aug 10, 2020

I've had a quick glance over the changes.

thanks!

I think we should first define what the AUTOCONF_ values are for the MSYS and Windows. They are the central information for all recipes and classes to judge on what platform is compiled (AUTOCONF_BUILD) and for which platform the executables/libraries are generated (AUTOCONF_HOST) (see autoconf documentation).

i am not sure about this. this AUTOCONF_ stuff comes from the autotools build-tool, doesn't it?
autotools doesn't support windows at all. yeah we could define this as a root-variable for bob, but hmm, at least, choosing the CMAKE_GENERATOR isn't a better solution of course :D

Quickly googling around lead me to *-*-mingw32 for native gcc builds and clang seems to use something like *-win32 for windows. It would be really good to enumerate the target triples. I think the CMake should make the decision about the "generator" based on this information. This decouples the toolchain and CMake class. Other build systems will face similar challenges so it makes sense to have a looser coupling between toolchain and cmake class.

Did you come up with *-pc-msys in plugins/multiarch.pyby yourself or is this already a standard somewhere?

maybe it is a good idea to use the git solution. git is very common, and available for all worlds: git-for-windows/msys2-runtime@6210daa

@jkloetzke
Copy link
Member

I think we should first define what the AUTOCONF_ values are for the MSYS and Windows. They are the central information for all recipes and classes to judge on what platform is compiled (AUTOCONF_BUILD) and for which platform the executables/libraries are generated (AUTOCONF_HOST) (see autoconf documentation).

i am not sure about this. this AUTOCONF_ stuff comes from the autotools build-tool, doesn't it?
autotools doesn't support windows at all. yeah we could define this as a root-variable for bob, but hmm, at least, choosing the CMAKE_GENERATOR isn't a better solution of course :D

It's coming from autotools but they can and should be used elsewhere too. They are used as central switches to define the host and target environment. If all classes consistently use these variables then there is hopefully no need to have extra variables for the different build systems.

Quickly googling around lead me to *-*-mingw32 for native gcc builds and clang seems to use something like *-win32 for windows. It would be really good to enumerate the target triples. I think the CMake should make the decision about the "generator" based on this information. This decouples the toolchain and CMake class. Other build systems will face similar challenges so it makes sense to have a looser coupling between toolchain and cmake class.
Did you come up with *-pc-msys in plugins/multiarch.pyby yourself or is this already a standard somewhere?

maybe it is a good idea to use the git solution. git is very common, and available for all worlds: git-for-windows/msys2-runtime@6210daa

Yes, this looks promising. We just have to come up with some triples for VS builds. Maybe x86_64-pc-win32? This also nicely reflects the fact that you are actually cross-compiling in your MSYS environment: from x86_64-pc-msys to x86_64-pc-win32.

BTW, IIRC CMake finds the installed visual studio automatically, right? Or do you have a real Visual Studio toolchain recipe? I have the vague feeling that when building with VS the build results are dependent on the VS version, right?

It would be good to have an example project that showcases the MSYS usage. Otherwise it's hard to tell if we're on the right track.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 10, 2020

Yes, this looks promising. We just have to come up with some triples for VS builds. Maybe x86_64-pc-win32? This also nicely reflects the fact that you are actually cross-compiling in your MSYS environment: from x86_64-pc-msys to x86_64-pc-win32.

We have to different between building with bob natively or in MSYS2 environment, havn't we?
x86_64-pc-win32 ... sounds like native windows msvc build.
x86_64-pc-msys ... the same like x86_64-pc-win32, but in MSYS2

BTW, IIRC CMake finds the installed visual studio automatically, right? Or do you have a real Visual Studio toolchain recipe? I have the vague feeling that when building with VS the build results are dependent on the VS version, right?

here i invested some time. strange stuff IMO. if we use cmake without -G (generator string), than cmake detects automatically the newest MSVC. If there is a special requirement to the compiler version we have to set this.

First: I guess we should JUST support Visual Studio 2019. VS2019 supports VS compiler versions of VS2015 and VS2017 by setting a toolset version. new since VS2019 is the following syntax: cmake -G"Visual Studio 16 2019" -A x64 -T v142

the system has completely changed since VS2019. now we can select older compiler versions of previous VS versions.
Before each VS installation had its own compiler.

CMAKE_GENERATOR: "Visual Studio 16 2019" --> FIX
CMAKE_GENERATOR_PLATFORM: "x64"
CMAKE_GENERATOR_TOOLSET: "v142"

x64: 64 bit
x86: 32 bit

v140: VS2015 compiler version
v141: VS2017 compiler version
v142: VS2019 compiler version

A problem. If we have a non-cmake module, like boost or qt4.
boost just requires the VS prompt (cmd), there are the env-vars INCLUDE, LIB, LIBPATH and PATH are set.
qt4 uses the b2, this one also requires this environment variables.

Problem, it is not possible to load this environment variables in MSYS2, because the vcvarsall.bat files could not executed successfully in MSYS2. there is a deprecated overview of paths inside the env-vars: https://renenyffenegger.ch/notes/Windows/development/Visual-Studio/environment-variables/index

i am searching for a solution to get INCLUDE, LIB, LIBPATH and PATH values by cmake by specifing the generator. but this doesn't match with the idea to select everything by AUTOCONF_ value.

Another problem: the compiler itself inside the VS version can be updated by M$ VS-Installer.
e.g.: VS2019 has installed on my PC currently the following versions: 14.22.27905, 14.23.28105, 14.25.28610
all versions > 14.16 are VS2019 compilers..

Next problem, just VS installation is just one part. the second part is the windows kit (sdk).
e.g. VS2010 uses the SDK v7.1. VS2019 uses v10. but here also there are different versions like: 10.0.16299, 10.0.17134, ....
normally CMake uses the newest one...

next problem: if i load the vcvarsall.bat in windows by regular way, and call CMake without a generator, than also the newest versions are selected and not this ones, I loaded by vcvarsall.bat

example for vcvars: vcvarsall.bat x64 -vcvars_ver=14.25

conclusion: windows and toolchains and env-vars is strange stuff.

our current solution is the following:

provideVars:
    CMAKE_GENERATOR: "Visual Studio 16 2019"
    CMAKE_GENERATOR_PLATFORM: "x64"
    CMAKE_GENERATOR_TOOLSET: "v142"

    # Visual Studio 2019 Win64 compiler - default installation paths
    # use "?" char for latest version
    VS_INCLUDE: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/?/include;C:/Program Files (x86)/Windows Kits/10/Include/?/shared;C:/Program Files (x86)/Windows Kits/10/Include/?/um;C:/Program Files (x86)/Windows Kits/10/Include/?/ucrt"
    VS_LIB: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/?/lib/x64;C:/Program Files (x86)/Windows Kits/10/Lib/?/um/x64;C:/Program Files (x86)/Windows Kits/10/Lib/?/ucrt/x64"
    VS_LIBPATH: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/?/lib/x64"
    VS_PATH: "/c/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/?/bin/HostX64/x64:/c/Program Files (x86)/Windows Kits/10/bin/?/x64"

all developers in the company have to use the default installation paths. we use VS2019 professional. for the problem, that the compiler-version can be updated automatically by M$, we use a bob-class, which search for the "?" char, goes into the directory, and selects the highest number and replaces this with the "?". xD that we export the VS_* vars to MSYS2 without the VS_

@jkloetzke
Copy link
Member

Wow. This Windows stuff is so f***** insane. 😭 I have to think about it.

Generally speaking the AUTOCONF_ variables won't be used to select a particular visual studio version. They are just to select the general host/target. Normally the CC/LD/... variables from the toolchain do the rest. But this is apparently different on Windows.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 11, 2020

i found something very interesting. if i build boost with the b2 tool, the tool will generate a "msvc-setup.bat" file.
in the file are the msvc paths defined for INCLUDE, PATH, LIBPATH and LIB. The batchfile is such simple, so it also can be loaded by MSYS2.
e.g. if i call ./b2.exe address-model=64 toolset=msvc-14.2 it get
bin.v2\standalone\msvc\msvc-14.2\address-model-64\architecture-x86\msvc-setup.bat
the content in the end, is the same like vcvarsall.bat would do under native windows.
but until now, i found no way to extract this from the full boost package.

UPDATE: i got it.

create the following files:

./boost-build.jam
BOOST_ROOT = $(.boost-build-file:D) ;
BOOST_BUILD = [ MATCH --boost-build=(.*) : $(ARGV) ] ;
BOOST_BUILD ?= tools/build/src ;
boost-build $(BOOST_BUILD) ;

./hello.cpp
int main()
{
    return 0;
}

./Jamroot.jam
exe hello : hello.cpp ;
clone `https://github.com/boostorg/build `to `tools/build`
goto tools/build
chmod +x bootstrap.bat
./bootstrap.bat
copy the b2 to root
./b2 toolset=msvc-<10.0 to 14.2> address-model=<32 or 64>
check the bin\standalone\msvc\msvc-<verion>\address-model-<address-model> directory
there is a msvc-setup.bat with exactly that content we need to build with msvc in MSYS2!

EDIT:
okay. also the msvc-setup.bat can not be "sourced" in MSYS2.... here is extra work necessary, again....

@jkloetzke
Copy link
Member

This is a total mess. I have the feeling that the settings must be somehow gathered by a plugin which calls vcvarsall.bat (or even vswhere.exe which seems to have a standard location) to fetch the values. The toolchain recipe calls the plugin to extract the right values and then provides them.

But CMake always seems to need its own settings. If it can't be done otherwise then we have to live with that. Interestingly the Visual Studio installation already comes with CMake.

Meson and other seem to use the variables provided by vcvarsall.bat. At least there seems to be some hope.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 11, 2020

yeah, but we need a way to source the vcvarsall.bat. it will not work out of the box in MSYS2. b2 (boost build) calls a cmd instance, in which the bat will called, followed by the build command - both in the same cmd instance.

@jkloetzke
Copy link
Member

I think we must spawn a cmd instance that calls vcvarsall and prints all variables. The output is then parsed by the plug-in.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 13, 2020

what do u think, should we implement this from the scratch by using vswhere and calling the vcvarsall.bat or should we use the b2 (boost build) tool, to get this functionality. in case of b2, we just have to convert the msvc-setup.bat to bash-syntax.

we also need a mapping. b2 selects just compiler versions. 10.0 - 14.2.
in CMake u have to know, where ur compiler is installed.

CMAKE_GENERATOR="Visual Studio 15 2017 Win64" is the same compiler like:

CMAKE_GENERATOR="Visual Studio 16 2019"
CMAKE_GENERATOR_PLATFORM: "x64"
CMAKE_GENERATOR_TOOLSET: "v141"

depending which Visual Studio u have installed.

EDIT: like i said:

First: I guess we should JUST support Visual Studio 2019

@jkloetzke
Copy link
Member

what do u think, should we implement this from the scratch by using vswhere and calling the vcvarsall.bat or should we use the b2 (boost build) tool, to get this functionality. in case of b2, we just have to convert the msvc-setup.bat to bash-syntax.

I think it should be implemented without any unnecessary external dependencies. I was thinking about a plugin that executes a single batch file that does the following:

  • execute vswhere.exe from the known location to find the toolset that we're interested in,
  • call vcvarsall.bat to fetch environment,
  • print environment to stdout.

The plugin can then parse stdout and get all the variables we're interested in.

we also need a mapping. b2 selects just compiler versions. 10.0 - 14.2.
in CMake u have to know, where ur compiler is installed.
...
EDIT: like i said:

First: I guess we should JUST support Visual Studio 2019

Yes. I think that's reasonable. Regarding the toolset version there still needs to be a special handling for CMake. All other build systems just use the environment variables.

The CMAKE_GENERATOR_PLATFORM can be inferred from AUTOTOOLS_HOST. I think the same can be done for the CMAKE_GENERATOR. Normally nothing is passed except for $AUTOTOOLS_HOST = *-win32 where VS2019 is used.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 14, 2020

plugin py-file:

from os.path import join
import subprocess

VSWHERE = "C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe"

WHITELIST = ["INCLUDE", "LIB", "LIBPATH", "PATH"]

def normalizeString(string):
    return string.strip().decode("utf-8")

def vsvars(args, **options):
    r = normalizeString(subprocess.check_output([VSWHERE, '-property', 'installationPath', '-version', '[16.0,17.0)']))
    r = subprocess.check_output([join(r, 'VC/Auxiliary/Build/vcvarsall.bat'), 'x64', '&&', 'set'])
    l = r.splitlines()
    result=[]
    for i in l:
        for j in WHITELIST:
            if normalizeString(i).startswith(j + "="):
                result.append(normalizeString(i))
    return ','.join(result)

manifest = {
    'apiVersion' : "0.15",
    'stringFunctions' : {
        "vsvars" : vsvars
    },
}

maybe we should make -version [16.0,17.0) to an option and x64 must be an option.
but here we need already the mapping stuff, i guess.

the interpreter class:

environment:
    VS_VARS: "$(vsvars)"

buildVars: [VS_VARS]
buildScript: |
    convert()
    {
        OLDIFS=$IFS
        IFS=';'
        for j in $1 ; do
            list=${list:+$list:}$(cygpath -u $j)
        done
        IFS=$OLDIFS
        echo $list
    }

    OLDIFS=$IFS
    IFS=','
    for i in $VS_VARS ; do
        envvar=${i%%=*}
        value=${i//$envvar=/}
        list=$(convert $value)

        old=$(printenv $envvar) || true
        if [[ "${old:-false}" != "false" ]] ; then
            if [[ $old == *";"* ]] ; then
                old=$(convert $old)
            fi
        fi
        export "$envvar=${old:+$old:}$list"
    done
    IFS=$OLDIFS

Is there a way to minimize the logging-output if i'm using -vv?
because of the loops the output is huge.

just optimized for MSYS2, will not work for native windows, maybe we should adapt this, too.

the line with printenv || true is a bit strange, but i got no better solution, if there is no variable in environment, that could be printed.

feedback welcome :)

@jkloetzke
Copy link
Member

I've tested a bit and I don't think you have to convert the paths in your bash script. Just gather all variables in the plugin, cache them and query them one by one (not tested):

import os, os.path
import subprocess

cache = {}

def vsvars(args, **options):
    varname = args[0]
    version = args[1]
    platform = args[2:]
    vswhere = os.path.join(os.environ["ProgramFiles(x86)"], "Microsoft Visual Studio/Installer/vswhere.exe")

    tag = (version, tuple(platform))
    if tag not in cache:
        r = subprocess.check_output([vswhere, '-property', 'installationPath', '-products', '*',
                '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', '-version', version],
            universal_newlines=True).strip()
        r = subprocess.check_output([os.path.join(r, 'VC/Auxiliary/Build/vcvarsall.bat')] +
                platform + ['&&', 'set'],
            universal_newlines=True)
        env = {}
        for l in r.splitlines():
            k,sep,v = l.strip().partition("=")
            if k == 'PATH':
                # convert to POSIX path to be mergeable
                v = subprocess.check_output(["cygpath", "-u", "-p", v], universal_newlines=True).strip()
            env[k] = v
        cache[tag] = env

    return env[varname]

Then in the toolchain you can:

environment:
    "INCLUDE" : "$(vsvars,INCLUDE,'[16.0,17.0)',x64)"
    "VS_PATH" : "$(vsvars,PATH,'[16.0,17.0)',x64)"

The only thing that needs special care is PATH. It is converted to a POSIX path by the plugin. This has to be appended manually to $PATH in the buildScript. The other variables can be taken as-is AFAICT.

I noticed that it takes quite a long time to fetch the variables. I think they should be cached somehow on disk. I'm just not sure what would invalidate them if the user updates, installs or removes toolsets.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 17, 2020

reviewed and tested. small issue:

-    return env[varname]
+        return env[varname]
+    return cache[tag][varname]

toolchain file:

privateEnvironment:
    PLATFORM: "x64"
    VERSION: "[16.0,17.0)"

provideVars:
    CMAKE_GENERATOR: "Visual Studio 16 2019"
    CMAKE_GENERATOR_PLATFORM: "${PLATFORM}"
    CMAKE_GENERATOR_TOOLSET: "v142"

    INCLUDE: "$(vsvars,INCLUDE,${VERSION},${PLATFORM})"
    LIBPATH: "$(vsvars,LIBPATH,${VERSION},${PLATFORM})"
    LIB: "$(vsvars,LIB,${VERSION},${PLATFORM})"
    VS_PATH: "$(vsvars,PATH,${VERSION},${PLATFORM})"
    
    CPPFLAGS: ...

class to activate environment:

buildVars: [INCLUDE, LIB, LIBPATH, VS_PATH]
buildScript: |
    export INCLUDE=$INCLUDE
    export LIB=$LIB
    export LIBPATH=$LIBPATH
    export PATH=$PATH:$VS_PATH

important to bring PATH in front of VS_PATH.

to support more than vs2019, we just have to replace VC/Auxiliary/Build/vcvarsall.bat string.
we have to search for vcvarsall.bat in VC. will work for >= vs2015 compilers (?installed by VS2019?).

mapping:

"[14.0,15.0)" --> vc140 --> compiler of VS2015
"[15.0,16.0)" --> vc141 --> compiler of VS2017
"[16.0,17.0)" --> vc142 --> compiler of VS2019
import glob
...
        r = subprocess.check_output([vswhere, '-legacy', '-property', 'installationPath', '-version', version],
            universal_newlines=True).strip()
        for filename in glob.glob(os.path.join(r, 'VC/**/vcvarsall.bat'), recursive = True):
            p = filename
            break
        r = subprocess.check_output([p] + platform + ['&&', 'set'],
            universal_newlines=True)

-products and -requires isn't important IMO. so we can activate -legacy.

just 1 more thing... could it a good idea, to give vsvars function the vc142 string and the function maps this to the range string "[16.0,17.0)"?

@jkloetzke
Copy link
Member

reviewed and tested. small issue:

👍

toolchain file:

Just a side note: while the usual provideVars will still work it is recommended to follow the new style to attach the toolchain specific variables directly to the toolchain. You can have a look at recipes/devel/cross-toolchain.yaml to see how it's used. This is useful in two respects: the variables will only be set if you really use the toolchain and it will enable to use the toolchain remapping. So it basically should look like:

   target-toolchain:
       path: "just_a_placeholder"
       environment:
           CMAKE_GENERATOR: "Visual Studio 16 2019"
           ...

class to activate environment:

No need to re-export variables unchanged. Also make sure to use quotes and append only if VS_PATH is set:

buildVars: [INCLUDE, LIB, LIBPATH, VS_PATH]
buildScript: |
    ${VS_PATH:+export PATH="$PATH:$VS_PATH"}

to support more than vs2019, we just have to replace VC/Auxiliary/Build/vcvarsall.bat string.

According to the Microsoft docs this path is valid for VS 2017 and 2019. Do we really have to support ancient versions too? I thought 2019 should be enough.

        r = subprocess.check_output([vswhere, '-legacy', '-property', 'installationPath', '-version', version],
            universal_newlines=True).strip()

-products and -requires isn't important IMO. so we can activate -legacy.

Not sure. I only installed the build tools and not the whole VS which should be enough to compile C/C++ code. For that you need the -products and -requires switches to find it. I would like to keep that. It would make sense, e.g. on a Jenkins slave.

just 1 more thing... could it a good idea, to give vsvars function the vc142 string and the function maps this to the range string "[16.0,17.0)"?

No, I don't think this is a good idea. Maybe someone wants to specify a more specific version in the future? Better keep the flexibility.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 17, 2020

could we make the legacy-mode optionally?

if arg[3]: True than -legacy else (default - empty arg or False): '-products', '*', '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64'
need help for implementation.

According to the Microsoft docs this path is valid for VS 2017 and 2019. Do we really have to support ancient versions too?

With Visual Studio 2019 we can install compilers 2015 and newer...

about the naming...
plugin name: "vsenv.py"
class name: "vsenv.yaml"
toolchain name: "devel/vs2019-toolchain.yaml"

would that be fine 4u?

for the toolchain file, we could provide this multipackage:

multiPackage:
    vc141:
        privateEnvironment:
            VERSION: "[15.0,16.0)"
            TOOLSET: "v141"

        multiPackage:
            x64:
                privateEnvironment:
                    PLATFORM: "x64"
            x86:
                privateEnvironment:
                    PLATFORM: "x86"

    vc142:
        privateEnvironment:
            VERSION: "[16.0,17.0)"
            TOOLSET: "v142"

        multiPackage:
            x64:
                privateEnvironment:
                    PLATFORM: "x64"
            x86:
                privateEnvironment:
                    PLATFORM: "x86"

or we could handle it by toolchain environment variables:

        privateEnvironment:
            VERSION: "${VERSION:-[16.0,17.0)}"
            TOOLSET: "${TOOLSET:-v142}"
            PLATFORM: "${TOOLSET:-x64}"
depend:
  - name: devel::vs2019-toolchain
    environment: 
        VERSION: "[15.0,16.0)"
        TOOLSET: "v141"
        PLATFORM: "x86"
    use: [tools]
    forward: True

It's hard for me to select the best solutions.

everything else look very nice, i would say. 👍

btw: how u bring color into the code-blocks :)

@jkloetzke
Copy link
Member

I've just added a tests/linux directory with some small smoke tests for CMake and meson. I would really like to get this extended and have a tests/msys which builds the same packages on Windows. That way we have some smoke tests where we can see that the Windows changes are working as expected and that nothing else breaks.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 20, 2020

I added the plugin and the toolchain file in current version. That's all I have so far.
Let me know... :)

@jkloetzke
Copy link
Member

👍 I'll hopefully look into it this evening.

@jkloetzke
Copy link
Member

Ok, I've looked into it this weekend and could simplify it quite a bit. The VS-Generator is not necessary if the environment is setup correctly. The result is here: https://github.com/jkloetzke/basement/tree/feature/cmakeWindowsSupport I've added the test case to tests/msys. This is far from complete and the LInux build is now broken.

I also tried to get meson working but this does not seem to work at all. Meson does not work in an msys environment. It feels like we will have to add Python as 3rd language to Bob so that we can build true cross-platform recipes...

@mahaase
Copy link
Contributor Author

mahaase commented Aug 24, 2020

The VS-Generator is not necessary if the environment is setup correctly.

What do u mean with VS-generator?

[[ "$AUTOCONF_HOST" == *-win32 ]] && i="$(cygpath -m $i)"

I guess, it should by *-msys.

            *-win32)
                CMAKE_SYSTEM_NAME=Windows
                ;;

is *-msys missing? But .... do we need them? who needs cross-compiling for windows?

The changes you made for calling cmake-configure, build and install, I do not understand :-/

the cpackage-class I do not understand so far. ... and is pkg-config supported for windows?

and what is meson? never heard about that before, should i know it?

@jkloetzke
Copy link
Member

The VS-Generator is not necessary if the environment is setup correctly.

What do u mean with VS-generator?

The CMake "Visual Studio 16 2019" generator. This generator does some magic to find the toolchain itself. No other build system does that. But if the environment is setup correctly then the "Ninja" CMake generator can be used directly and CMake behaves like other build systems too.

[[ "$AUTOCONF_HOST" == *-win32 ]] && i="$(cygpath -m $i)"

I guess, it should by *-msys.

No. We build for x86_64-pc-win32 (AUTOCONF_HOST) on x86_64-pc-msys (AUTOCONF_BUILD).

            *-win32)
                CMAKE_SYSTEM_NAME=Windows
                ;;

is *-msys missing? But .... do we need them? who needs cross-compiling for windows?

You do in fact cross compile. Your build system, including Bob, runs on msys. This is a different ABI than what you are compiling for: win32 - native windows binaries without any msys dependency.

the cpackage-class I do not understand so far. ... and is pkg-config supported for windows?

This is the common class for all c/c++ based packages. And no, pkg-config is not supported on Windows. 😀

and what is meson? never heard about that before, should i know it?

This is just another build system that gains traction. It is like autotools and CMake. I used it as a litmus test to see if the changes go in the right direction, i.e. that they are general enough to cover not only CMake. Even if it is not a use case for you it should be possible to compile packages other than CMake too on Windows. But because meson and msys are not compatible it was deemed to fail...

@mahaase
Copy link
Contributor Author

mahaase commented Aug 24, 2020

This is far from complete and the LInux build is now broken.

I build the linux+freertos demo project on my native linux pc with my feature branch:

Build result is in dev/dist/demo/linux+freertos/1/workspace
Duration: 0:27:50.791080, 27 checkouts (0 overrides active), 57 packages built, 1 downloaded.

This is just another build system that gains traction. It is like autotools and CMake. I used it as a litmus test to see if the changes go in the right direction, i.e. that they are general enough to cover not only CMake. Even if it is not a use case for you it should be possible to compile packages other than CMake too on Windows. But because meson and msys are not compatible it was deemed to fail...

Which build-systems are supported in windows and MSYS. I just know CMake?! Meson supports Windows, but not MSYS2? What is the reason there - i guess it can just be an issue with the path-strings.

The CMake "Visual Studio 16 2019" generator. This generator does some magic to find the toolchain itself. No other build system does that. But if the environment is setup correctly then the "Ninja" CMake generator can be used directly and CMake behaves like other build systems too.

indeed. that is a point! i also seen that. if we build a project with boost (b2) and CMake, we saw, that both systems doesn't used the same information to find compiler a.s.o.
BUT: i havn't seen so far, that i can setup CMake without the generator and platform stuff... :-/ hm, maybe that is possible, would be nice - i guess CMake is ignoring anything... (just the experience of my tests so far.)

CC=cl
CXX=cl
load the environment

works for VS2019 compiler, but not for VS2015 compiler. there is an issue in the vcvarsall.bat files. the sdk 10.0 will not loaded fully, so rc.exe and mt.exe are missing. I love that windows stuff...
If u search online for this bug, u will fine a ton of sites, with exactly this issue: e.g. xmake-io/xmake#225 (comment)

@jkloetzke
Copy link
Member

This is far from complete and the LInux build is now broken.

I build the linux+freertos demo project on my native linux pc with my feature branch:

This project does not use CMake. I've pushed an update for my branch that fixes the CMake class and cleans it further up. I still have to fix the meson build of the tests on Linux but it's going in a direction which I'm comfortable with. Please have a look.

Which build-systems are supported in windows and MSYS. I just know CMake?! Meson supports Windows, but not MSYS2? What is the reason there - i guess it can just be an issue with the path-strings.

Currently it's CMake but meson can be used on Windows too. Just not for msys directly.

works for VS2019 compiler, but not for VS2015 compiler. there is an issue in the vcvarsall.bat files. the sdk 10.0 will not loaded fully, so rc.exe and mt.exe are missing. I love that windows stuff...
If u search online for this bug, u will fine a ton of sites, with exactly this issue: e.g. xmake-io/xmake#225 (comment)

Can't we just apply the workaround in the vsvars plugin too? Looks like there is "just" something missing in %PATH%..?

@mahaase
Copy link
Contributor Author

mahaase commented Aug 25, 2020

CMAKE_INSTALL_PREFIX="/usr"

is there a reason, why my u doesn't used my solution:

CMAKE_INSTALL_PREFIX="\/"

the backslash prevents the converting to C:/msys64/usr and the usr is not necessary, refer here:
https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html?#special-cases

For

other than the SYSCONFDIR, LOCALSTATEDIR and RUNSTATEDIR, the value of CMAKE_INSTALL_ is prefixed with usr/ if it is not user-specified as an absolute path. For example, the INCLUDEDIR value include becomes usr/include. This is required by the GNU Coding Standards

if we prefix the /usr, SYSCONFDIR will be /usr/etc.

But, we have to make CMAKE_INSTALL_PREFIX variable. i would prefer:

CMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX:-\/}"

so a module, that doesn't support GNUInstallDirs, has the option to set a path to e.g. ${PWD}/../install/usr.
But than we have to remove the --prefix argument.


[[ "$AUTOCONF_HOST" == *-win32 ]] && i="$(cygpath -m $i)"

what is with native windows? it will not support cygpath tool. shouldn't we check [[ "$AUTOCONF_BUILD == *-msys ]].


what is about this:

-DCMAKE_PREFIX_PATH="/usr/lib/cmake;/usr"

for find_package we use this CMake install path structure: <prefix>/(lib/<arch>|lib|share)/cmake/<name>*/ (U) this one is just supported for UNIX. For Windows we can use this: <prefix>/<name>*/ (W) by adding the CMAKE_PREFIX_PATH /usr/lib/cmake. For UNIX we add /usr.


DESTDIR="${PWD}/../install" cmake \
    ${INSTALL_COMPONENT:+-DCOMPONENT="$INSTALL_COMPONENT"} \
    -P cmake_install.cmake

why not using the common CMake way?

        if [[ -n "$INSTALL_TARGET" ]] ; then
            if [[ "$INSTALL_TARGET" != "install" ]] ; then
                COMPONENT="--component $INSTALL_TARGET"
            fi
            cmake --install . \
                --config ${CMAKE_BUILD_TYPE:-Bob} \
                --prefix ${CMAKE_INSTALL_PREFIX:-"../install"} \
                ${COMPONENT:+${COMPONENT}} \
                ${INSTALL_OPTIONS:+"${INSTALL_OPTIONS[@]}"}

Ninja:

have u tested the tests/msys?
the MSYS2 ninja is broken, im my tests.

the self-built ninja wasn't used.
so we have to add the dependency somewhere? something like the rootrecipe in linux?!

for building Ninja we use Ninja.
If I add a downloaded Ninja to PATH, I can build Ninja :)

We need the bootstrap.
This one doesn't support MSYS2. But I got it fixed:

diff --git a/recipes/devel/ninja.yaml b/recipes/devel/ninja.yaml
index a283d72..aa2e454 100644
--- a/recipes/devel/ninja.yaml
+++ b/recipes/devel/ninja.yaml
@@ -1,18 +1,23 @@
-inherit: [cmake]
+inherit: [cmake, patch]

 metaEnvironment:
     PKG_VERSION: "1.10.0"

 checkoutSCM:
     scm: url
-    url: https://github.com/ninja-build/ninja/archive/v1.10.0.tar.gz
+    url: https://github.com/ninja-build/ninja/archive/v${PKG_VERSION}.tar.gz
     digestSHA256: 3810318b08489435f8efc19c05525e80a993af5a55baa0dfeae0465a9d45f99f
-    stripComponents: 1

+checkoutDeterministic: True
+checkoutScript: |
+    patchApplySeries $<<ninja/*.patch>>
+
+buildVars: [PKG_VERSION]
 buildScript: |
-    cmakeBuild -n "$1" # no install target!
+    cp -r $1/ninja-${PKG_VERSION}/* .
+    python configure.py --bootstrap
     mkdir -p install/usr/bin
-    cp build/ninja install/usr/bin/
+    cp ninja install/usr/bin/

 packageScript: |
     cmakePackageTgt
diff --git a/recipes/devel/ninja/0001-support-msys.patch b/recipes/devel/ninja/0001-support-msys.patch
new file mode 100644
index 0000000..16cf86a
--- /dev/null
+++ b/recipes/devel/ninja/0001-support-msys.patch
@@ -0,0 +1,130 @@
+--- workspace/ninja-1.10.0/configure.py        2020-01-27 11:37:35.000000000 +0100
++++ workspace/ninja-1.10.0/configure.py        2020-08-26 17:15:00.287544700 +0200
+@@ -64,6 +64,8 @@
+             self._platform = 'os400'
+         elif self._platform.startswith('dragonfly'):
+             self._platform = 'dragonfly'
++        elif self._platform.startswith('msys'):
++            self._platform = 'msvc'
+
+     @staticmethod
+     def known_platforms():
+@@ -83,8 +85,11 @@
+     def is_msvc(self):
+         return self._platform == 'msvc'
+
++    def is_msys():
++        return sys.platform.startswith('msys')
++
+     def msvc_needs_fs(self):
+-        popen = subprocess.Popen(['cl', '/nologo', '/?'],
++        popen = subprocess.Popen(['cl', '-nologo', '-?'],
+                                  stdout=subprocess.PIPE,
+                                  stderr=subprocess.PIPE)
+         out, err = popen.communicate()
+@@ -142,9 +147,9 @@
+         return self.writer.newline()
+
+     def variable(self, key, val):
+-        # In bootstrap mode, we have no ninja process to catch /showIncludes
++        # In bootstrap mode, we have no ninja process to catch -showIncludes
+         # output.
+-        self.vars[key] = self._expand(val).replace('/showIncludes', '')
++        self.vars[key] = self._expand(val).replace('-showIncludes', '')
+         return self.writer.variable(key, val)
+
+     def rule(self, name, **kwargs):
+@@ -306,32 +311,32 @@
+     n.variable('ar', configure_env.get('AR', 'ar'))
+
+ if platform.is_msvc():
+-    cflags = ['/showIncludes',
+-              '/nologo',  # Don't print startup banner.
+-              '/Zi',  # Create pdb with debug info.
+-              '/W4',  # Highest warning level.
+-              '/WX',  # Warnings as errors.
+-              '/wd4530', '/wd4100', '/wd4706', '/wd4244',
+-              '/wd4512', '/wd4800', '/wd4702', '/wd4819',
++    cflags = ['-showIncludes',
++              '-nologo',  # Don't print startup banner.
++              '-Zi',  # Create pdb with debug info.
++              '-W4',  # Highest warning level.
++              '-WX',  # Warnings as errors.
++              '-wd4530', '-wd4100', '-wd4706', '-wd4244',
++              '-wd4512', '-wd4800', '-wd4702', '-wd4819',
+               # Disable warnings about constant conditional expressions.
+-              '/wd4127',
++              '-wd4127',
+               # Disable warnings about passing "this" during initialization.
+-              '/wd4355',
++              '-wd4355',
+               # Disable warnings about ignored typedef in DbgHelp.h
+-              '/wd4091',
+-              '/GR-',  # Disable RTTI.
++              '-wd4091',
++              '-GR-',  # Disable RTTI.
+               # Disable size_t -> int truncation warning.
+               # We never have strings or arrays larger than 2**31.
+-              '/wd4267',
+-              '/DNOMINMAX', '/D_CRT_SECURE_NO_WARNINGS',
+-              '/D_HAS_EXCEPTIONS=0',
+-              '/DNINJA_PYTHON="%s"' % options.with_python]
++              '-wd4267',
++              '-DNOMINMAX', '-D_CRT_SECURE_NO_WARNINGS',
++              '-D_HAS_EXCEPTIONS=0',
++              '-DNINJA_PYTHON="%s"' % options.with_python]
+     if platform.msvc_needs_fs():
+-        cflags.append('/FS')
+-    ldflags = ['/DEBUG', '/libpath:$builddir']
++        cflags.append('-FS')
++    ldflags = ['-DEBUG', '-libpath:$builddir']
+     if not options.debug:
+-        cflags += ['/Ox', '/DNDEBUG', '/GL']
+-        ldflags += ['/LTCG', '/OPT:REF', '/OPT:ICF']
++        cflags += ['-Ox', '-DNDEBUG', '-GL']
++        ldflags += ['-LTCG', '-OPT:REF', '-OPT:ICF']
+ else:
+     cflags = ['-g', '-Wall', '-Wextra',
+               '-Wno-deprecated',
+@@ -419,9 +424,9 @@
+
+ if platform.is_msvc():
+     n.rule('cxx',
+-        command='$cxx $cflags -c $in /Fo$out /Fd' + built('$pdb'),
++        command='$cxx $cflags -c $in -Fo$out -Fd' + built('$pdb'),
+         description='CXX $out',
+-        deps='msvc'  # /showIncludes is included in $cflags.
++        deps='msvc'  # -showIncludes is included in $cflags.
+     )
+ else:
+     n.rule('cxx',
+@@ -433,7 +438,7 @@
+
+ if host.is_msvc():
+     n.rule('ar',
+-           command='lib /nologo /ltcg /out:$out $in',
++           command='lib -nologo -ltcg -out:$out $in',
+            description='LIB $out')
+ elif host.is_mingw():
+     n.rule('ar',
+@@ -447,7 +452,7 @@
+
+ if platform.is_msvc():
+     n.rule('link',
+-        command='$cxx $in $libs /nologo /link $ldflags /out:$out',
++        command='$cxx $in $libs -nologo -link $ldflags -out:$out',
+         description='LINK $out')
+ else:
+     n.rule('link',
+@@ -690,7 +695,10 @@
+     if platform.can_rebuild_in_place():
+         rebuild_args.append('./ninja')
+     else:
+-        if platform.is_windows():
++        if platform.is_msys:
++            bootstrap_exe = './ninja.bootstrap.exe'
++            final_exe = './ninja.exe'
++        elif platform.is_windows():
+             bootstrap_exe = 'ninja.bootstrap.exe'
+             final_exe = 'ninja.exe'
+         else:

this fix will not break windows build, i guess.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 25, 2020

there is another problem. against my hope... the vswhere.exe tool doesn't show the installation path of the VS compiler, it shows the path to the VS installation.

so if i ask for version "[15.0,16.0)" i don't get the location of the vs2017 compiler, which was installed by VS2019.

so my toolchain file is wrong, if we just want to support VS2019 installation with included compilers of vs2015, vs2017 and vs2019.

the legacy mode is just to support older VS installations.

the resulting problem: I have to call all the time the same vcvarsall.bat file. so how i can choose the compiler version without setting the CMAKE_GENERATOR_TOOLSET variable?

cc, cxx = cl will always select ... hmm? maybe the newest vs2019 compiler?

and just setting the CMAKE_GENERATOR_TOOLSET will also not work in combination of CMAKE_GENERATOR=Ninja.
so we are limited to the newest installed compiler version if we are using Ninja?

SIDENOTE:

cmake -G"Visual Studio 16 2019" -A x64 -T v140 ..\app
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.18363.
-- The C compiler identification is MSVC 19.0.24245.0
-- The CXX compiler identification is MSVC 19.0.24245.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64/cl.exe -- works
cmake -G"Visual Studio 16 2019" -A x64 -T v141 ..\app
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.18363.
-- The C compiler identification is MSVC 19.16.27040.0
-- The CXX compiler identification is MSVC 19.16.27040.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.16.27023/bin/HostX64/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.16.27023/bin/HostX64/x64/cl.exe -- works
cmake -G"Visual Studio 16 2019" -A x64 -T v142 ..\app
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.18363.
-- The C compiler identification is MSVC 19.27.29111.0
-- The CXX compiler identification is MSVC 19.27.29111.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.27.29110/bin/Hostx64/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.27.29110/bin/Hostx64/x64/cl.exe -- works
cmake -G"Visual Studio 16 2019" -A Win32 -T v140 ..\app
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.18363.
-- The C compiler identification is MSVC 19.0.24245.0
-- The CXX compiler identification is MSVC 19.0.24245.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64_x86/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64_x86/cl.exe -- works

--> this is Win32 (32-bit) it isn't necessary to load the vcvarsall.bat with "x86".
maybe the default compiler for "Ninja" can be switched to 32-bit, if we call vcvarsall.bat with "x86" argument.

funny, hmh? no idea how CMake extracts this information.

@mahaase
Copy link
Contributor Author

mahaase commented Aug 25, 2020

conclusion:

defaults:

  • support VS2019 with latest compiler
  • default CMAKE_GENERATOR is "Ninja"
  • we just should use ninja for building, if CMAKE_GENERATOR is default, otherwise we should use cmake
  • variable CMAKE_GENERATOR for overwriting from recipe
  • variable/optional CMAKE_GENERAOTR_TOOLSET and CMAKE_GENERAOTR_PLATFORM for overwriting from recipe
  • we just need vswhere -version [16.0,17.0), but keep it variable for overwriting/reusing by different recipes
  • default is "x64" - NOTE there is no CMAKE_GENERAOTR_PLATFORM "x86", it is called "Win32" 🙄
  • vs2019-toolset.yaml should not provide multiPackages, but we can change to default by using:
- depends: 
  - name: devel::vs2019-toolchain
    environment:
      CMAKE_GENERATOR: <...>
      CMAKE_GENERATOR_*: <...>
    use|forward:<...>

@mahaase
Copy link
Contributor Author

mahaase commented Aug 25, 2020

maybe u could live with that?

diff --git a/classes/cmake.yaml b/classes/cmake.yaml
index 2516cac..0a81724 100644
--- a/classes/cmake.yaml
+++ b/classes/cmake.yaml
@@ -1,24 +1,18 @@
 inherit: [cpackage, ninja, install]

 buildTools: [cmake]
-buildVars: [AUTOCONF_HOST, CC, CXX, BUILD_SHARED_LIBS]
+buildVars: [CMAKE_GENERATOR, CMAKE_GENERATOR_PLATFORM, CMAKE_GENERATOR_TOOLSET,
+    CMAKE_INSTALL_PREFIX, CMAKE_BUILD_TYPE,
+    AUTOCONF_HOST, AUTOCONF_BUILD, CC, CXX, BUILD_SHARED_LIBS]
 buildScript: |
     # Make sure CMake finds other stuff by its own logic too
     CMAKE_FIND_ROOT_PATH=
     for i in "${@:2}" ; do
         # CMake needs win paths if we are in MSYS2
-        [[ "$AUTOCONF_HOST" == *-win32 ]] && i="$(cygpath -m $i)"
+        [[ "$AUTOCONF_BUILD" == *-msys ]] && i="$(cygpath -m $i)"
         CMAKE_FIND_ROOT_PATH+="${CMAKE_FIND_ROOT_PATH:+;}$i"
     done

-    # This looks odd but it prevents MSYS from converting /usr to C:\msys64\usr
-    # (or wherever MSYS was installed).
-    if [[ "$AUTOCONF_HOST" == *-win32 ]] ; then
-        CMAKE_INSTALL_PREFIX="C:/usr"
-    else
-        CMAKE_INSTALL_PREFIX="/usr"
-    fi
-
     # CMake does not honor CPPFLAGS! Merge them with C(XX)FLAGS.
     if [ "${CPPFLAGS:+true}" ] ; then
         CFLAGS+=" ${CPPFLAGS}"
@@ -96,22 +90,50 @@ buildScript: |
         mkdir -p build install
         pushd build

+        if [[ ${CMAKE_GENERATOR:-} == "Visual Studio"* ]] ; then
+            # since VS2019 we can select the platform and target by special variables
+            OPTIONS+=( ${CMAKE_GENERATOR_PLATFORM:+-A"${CMAKE_GENERATOR_PLATFORM}"} )
+            OPTIONS+=( ${CMAKE_GENERATOR_TOOLSET:+-T"${CMAKE_GENERATOR_TOOLSET}"} )
+            OPTIONS+=( -DCMAKE_CONFIGURATION_TYPES:STRING="Debug;Release;RelWithDebInfo;MinSizeRel;Bob" )
+        else
+            # windows does not support a sigle build type, we have to select the
+            # current type with cmake --build . --config
+            OPTIONS+=( -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE:-Bob} )
+        fi
+
+        # for find_package we use this cmake install path structure:
+        # <prefix>/(lib/<arch>|lib|share)/cmake/<name>*/ (U)
+        # this one is just supported for UNIX. For Windows we can use this:
+        # <prefix>/<name>*/ (W)
+        # by adding the CMAKE_PREFIX_PATH /usr/lib/cmake. For UNIX we add /usr.
         cmake "$1" \
-            -G Ninja \
+            -G"${CMAKE_GENERATOR:-Ninja}" \
             ${CMAKE_TOOLCHAIN_FILE:+-DCMAKE_TOOLCHAIN_FILE="$CMAKE_TOOLCHAIN_FILE"} \
             -DCMAKE_FIND_ROOT_PATH="$CMAKE_FIND_ROOT_PATH" \
-            -DCMAKE_BUILD_TYPE=Bob \
-            -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_PREFIX" \
+            -DCMAKE_PREFIX_PATH="/usr/lib/cmake;/usr;/" \
+            -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX:-"\/"} \
             -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS \
+            ${OPTIONS:+"${OPTIONS[@]}"} \
             "${@:2}"

-        ninjaParallel ${MAKE_OPTIONS:+"${MAKE_OPTIONS[@]}"} \
-            ${MAKE_TARGETS:+"${MAKE_TARGET[@]}"}
+        if [[ "${CMAKE_GENERATOR:-Ninja}" == "Ninja" ]] ; then
+            ninjaParallel ${MAKE_OPTIONS:+"${MAKE_OPTIONS[@]}"} \
+                ${MAKE_TARGETS:+"${MAKE_TARGET[@]}"}
+        else
+            cmake --build . --parallel "${MAKE_JOBS-$(nproc)}" \
+                --config ${CMAKE_BUILD_TYPE:-Bob} \
+                ${MAKE_TARGETS:+--target "${MAKE_TARGETS[@]}"} \
+                ${MAKE_OPTIONS:+"${MAKE_OPTIONS[@]}"}
+        fi

         if [[ -n "$INSTALL" ]] ; then
-            DESTDIR="${PWD}/../install" cmake \
-                ${INSTALL_COMPONENT:+-DCOMPONENT="$INSTALL_COMPONENT"} \
-                -P cmake_install.cmake
+            if [[ "$INSTALL_COMPONENT" != "install" ]] ; then
+                COMPONENT="--component $INSTALL_COMPONENT"
+            fi
+            cmake --install . \
+                --config ${CMAKE_BUILD_TYPE:-Bob} \
+                --prefix ${CMAKE_INSTALL_PREFIX:-"${PWD}/../install"} \
+                ${COMPONENT:+${COMPONENT}}
         fi
         popd
     }
diff --git a/recipes/devel/vs2019-toolchain.yaml b/recipes/devel/vs2019-toolchain.yaml
index 4fe71ab..b633cb4 100644
--- a/recipes/devel/vs2019-toolchain.yaml
+++ b/recipes/devel/vs2019-toolchain.yaml
@@ -10,12 +10,20 @@ packageVars: [PLATFORM, VERSION]
 packageScript: |
     echo "$PLATFORM $VERSION" > version.txt

+privateEnvironment:
+    VERSION: "[16.0,17.0)"
+    PLATFORM: "x64"
+
 provideTools:
     target-toolchain:
         path: "just_a_placeholder"
         environment:
             AUTOCONF_HOST: "x64_64-pc-win32"

+            CMAKE_GENERATOR: "${CMAKE_GENERATOR:-}"
+            CMAKE_GENERATOR_PLATFORM: "${CMAKE_GENERATOR_PLATFORM:-}"
+            CMAKE_GENERATOR_TOOLSET: "${CMAKE_GENERATOR_TOOLSET:-}"
+
             INCLUDE: "$(vsvars,INCLUDE,${VERSION},${PLATFORM},${LEGACY:-False})"
             LIBPATH: "$(vsvars,LIBPATH,${VERSION},${PLATFORM},${LEGACY:-False})"
             LIB: "$(vsvars,LIB,${VERSION},${PLATFORM},${LEGACY:-False})"
@@ -28,42 +36,3 @@ provideTools:
             CFLAGS: "-O$(if-then-else,$(eq,${BASEMENT_OPTIMIZE},0),d,${BASEMENT_OPTIMIZE})$(if-then-else,${BASEMENT_DEBUG}, -Zi,) -W3"
             CXXFLAGS: "-O$(if-then-else,$(eq,${BASEMENT_OPTIMIZE},0),d,${BASEMENT_OPTIMIZE})$(if-then-else,${BASEMENT_DEBUG}, -Zi,) -W3"
             LDFLAGS: ""
-
-multiPackage:
-    vc140:
-        privateEnvironment:
-            VERSION: "[14.0,15.0)"
-            LEGACY: "True"
-
-        multiPackage:
-            x64:
-                privateEnvironment:
-                    PLATFORM: "x64"
-            x86:
-                privateEnvironment:
-                    PLATFORM: "x86"
-
-    vc141:
-        privateEnvironment:
-            VERSION: "[15.0,16.0)"
-            LEGACY: "True"
-
-        multiPackage:
-            x64:
-                privateEnvironment:
-                    PLATFORM: "x64"
-            x86:
-                privateEnvironment:
-                    PLATFORM: "x86"
-
-    vc142:
-        privateEnvironment:
-            VERSION: "[16.0,17.0)"
-
-        multiPackage:
-            x64:
-                privateEnvironment:
-                    PLATFORM: "x64"
-            x86:
-                privateEnvironment:
-                    PLATFORM: "x86"
diff --git a/tests/linux/layers/self b/tests/linux/layers/self
index 1b20c9f..36dc815 120000
--- a/tests/linux/layers/self
+++ b/tests/linux/layers/self
@@ -1 +1 @@
-../../../
\ No newline at end of file
+../../../
diff --git a/tests/msys/recipes/cmake/greeter.yaml b/tests/msys/recipes/cmake/greeter.yaml
index ce05c1c..bce5a88 100644
--- a/tests/msys/recipes/cmake/greeter.yaml
+++ b/tests/msys/recipes/cmake/greeter.yaml
@@ -5,7 +5,7 @@ depends:
     - name: devel::cmake-win64
       use: [tools]
       forward: True
-    - name: devel::vs2019-toolchain-vc142-x64
+    - name: devel::vs2019-toolchain
       use: [environment, tools]
       forward: True
     - cmake::libgreet-dev
diff --git a/tests/msys/recipes/meson/greeter.yaml b/tests/msys/recipes/meson/greeter.yaml
index 98bd4cd..f82c333 100644
--- a/tests/msys/recipes/meson/greeter.yaml
+++ b/tests/msys/recipes/meson/greeter.yaml
@@ -5,7 +5,7 @@ depends:
     - name: devel::meson
       use: [tools]
       forward: True
-    - name: devel::vs2019-toolchain-vc142-x64
+    - name: devel::vs2019-toolchain
       use: [environment, tools]
       forward: True
     - meson::libgreet
diff --git a/tests/src/libgreet/CMakeLists.txt b/tests/src/libgreet/CMakeLists.txt
index 086a73d..fbd1862 100755
--- a/tests/src/libgreet/CMakeLists.txt
+++ b/tests/src/libgreet/CMakeLists.txt
@@ -54,7 +54,7 @@ configure_file(LibGreetConfig.cmake.in
   COPYONLY
 )

-set(ConfigPackageLocation lib/cmake/LibGreet)
+set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/LibGreet)
 install(EXPORT LibGreetTargets
   FILE
     LibGreetTargets.cmake
diff --git a/tests/src/libholler/CMakeLists.txt b/tests/src/libholler/CMakeLists.txt
index ae9b6a4..b71f294 100644
--- a/tests/src/libholler/CMakeLists.txt
+++ b/tests/src/libholler/CMakeLists.txt
@@ -48,7 +48,7 @@ configure_file(LibHollerConfig.cmake.in
   COPYONLY
 )

-set(ConfigPackageLocation lib/cmake/LibHoller)
+set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/LibHoller)
 install(EXPORT LibHollerTargets
   FILE
     LibHollerTargets.cmake

note: do not use static paths for cmake, ${CMAKE_INSTALL_LIBDIR} instead of lib. so cmake willl automatically prefix the /usr if necessary.

@waruqi
Copy link

waruqi commented Aug 25, 2020

Which build-systems are supported in windows and MSYS. I just know CMake?! Meson supports Windows, but not MSYS2? What is the reason there - i guess it can just be an issue with the path-strings.

xmake can also be obtained and used on windows/msys.

@jkloetzke
Copy link
Member

maybe u could live with that?

To be honest: no. 😄 I don't want to treat CMake in any way special. And I still think it is not necessary. I've updated the vs2019-toolchain and the v141 and v142 toolchain versions do work here now. I didn't bother to test v140. I'm pretty sure it works too. I also added ninja to the basement::rootrecipe class which now selects the right tools based on the host platform.

I also moved the tools to recipes/devel/win/... to keep them separated a bit.

note: do not use static paths for cmake, ${CMAKE_INSTALL_LIBDIR} instead of lib. so cmake willl automatically prefix the /usr if necessary.

Why? Using a relative path will let CMake add the prefix. It compiles on Linux and Windows(msys) here. Why should we ever use ${CMAKE_INSTALL_LIBDIR}? CMake will search all paths on all platforms. The (W) and (U) indicators are suggestions AFAICT. I deliberately created the tests from the cmake documentation. If some of your modules need to set CMAKE_PREFIX_PATH then it should be done in the project, possibly by a dedicated class...

@mahaase
Copy link
Contributor Author

mahaase commented Aug 28, 2020

first of all... wow. impressive performance 👍

just 3 small issues..


-AUTOCONF_HOST: "x64_64-pc-win32"
+AUTOCONF_HOST: "x86_64-pc-win32"

and with the changes in the "rootrecipe", the "bob_example_embedded" has the issue now, that "host-toolchain" will be needed, but isn't available. for linux i guess the compat or sandbox-toolchain will do this?!


again to the "/" vs "(C:)/usr" prefix:
https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html?#special-cases

In my test, i used: install(FILES doc/mainpage.txt TYPE SYSCONF) and this results in:

-- Installing: C:/msys64-1/home/mhaase/ws/bob-example-embedded/dev/build/fdt/example/lib-dev/x86_64-pc-win32/1/workspace/build/../install/usr/etc/mainpage.txt

/usr/etc is not correct for GNU paths IMO, but if i just use the "/", the "usr" will be added automatically by cmake, but it will not be removed automatically. but this just seems to work, if we just use the CMAKE_INSTALL_*DIR variables and not e.g. "lib" directly. 🙄

so the only cross-platform and working solution is the backslash-slash variant as far as i know:

CMAKE_INSTALL_PREFIX="\/"

one cool thing, it works for linux and windows.

but now we also need the -DCMAKE_PREFIX_PATH="/;/usr", that CMakes find_* will find the stuff.

@mahaase
Copy link
Contributor Author

mahaase commented Sep 21, 2020

push. i am back from vacation :)
what's with my last comments?

@jkloetzke
Copy link
Member

I haven't looked too deeply into it. I have a number of changes pending that will collide with this PR. Once they have landed I will pick up here...

jkloetzke and others added 9 commits October 26, 2020 19:26
When using ninja for cmake packages it would create a circular
dependency on itself. Fortunately ninja can be bootstrapped without any
external build tool.
Works like the make class. We use the Kitware fork of ninja that has
the job server support integrated.
This changes the "cmakeBuild" options slightly. Should typically be
faster than make, especially if nothing has changed.
Otherwise incremenatal builds will not prune stale files.
Always hide exported symbols because this is the default on Windows. Use
appropriate export/import definitions instead. This temporarily breaks
the meson build.
The CMake explample should build on Windows/MSYS too.
@jkloetzke
Copy link
Member

I've directly updated the pull request with the latest changes. I hope everything is addressed. Please test...

@mahaase
Copy link
Contributor Author

mahaase commented Nov 10, 2020

hey! thanks for the great work. nearly everything looks very good in my tests.

The only thing is the scenarion to use: install(FILES doc/MainPage.md TYPE SYSCONF) with the expectation to install into /etc directory.

But current result is /usr/etc:

-- Installing: C:/msys64-1/home/mhaase/ws/bob-example-embedded/dev/build/fdt/example/lib-dev/x86_64-pc-win32/1/workspace/build/../install/usr/etc/MainPage.md
~/ws/bob-example-embedded/dev/build/fdt/example/lib-dev/x86_64-pc-win32/1/workspace

It is also possible to use the // instead of //usr, if -DCMAKE_PREFIX_PATH="/;/usr" is added.

why u want the /usr for CMAKE_INSTALL_PREFIX. In my test, it is not possible to install something to /etc or /var (in CMake: SYSCONFDIR or LOCALSTATEDIR)

yes, in case of / for the CMAKE_INSTALL_PREFIX we have to use for install destinations the CMake GNUInstallDirs variables.

otherwise a DESTINATION lib would be installed to /lib not to /usr/lib.
a DESTINATION ${LIBDIR} will install into /usr/lib automatically.

In the end it is up to you, that is just how I understood CMakes GNUInstallDirs.
Your implementation has the disadvantage, that it isn't possible to install something not into /usr directory

@jkloetzke
Copy link
Member

I think the "/usr" prefix should be kept on Linux builds. OTOH a prefix is somehow useless on Windows. In any case the prefix should be consistent throughout the project. If I understand correctly you only need to set CMAKE_PREFIX_PATH if different prefix paths are used simultaneously in the same project. I would not like to support that, though.

I find it surprising that install(FILES doc/MainPage.md TYPE SYSCONF) does not do the right thing. Maybe we should set CMAKE_INSTALL_SYSCONFDIR to the right absolute path (/etc) unconditionally. That should solve the problem. I did not test if this works, though.

@mahaase
Copy link
Contributor Author

mahaase commented Nov 16, 2020

okay I'm fine! 👍

indeed, this works: -DCMAKE_INSTALL_SYSCONFDIR="//etc" \ for MSYS2.

but maybe we have not to set this inside the class. We could also set this manually inside the project, if necessary!

@mahaase
Copy link
Contributor Author

mahaase commented Nov 25, 2020

soooo, when this will go live? :)

@jkloetzke
Copy link
Member

The meson build of the example needs to be fixed and I have to test here if it breaks anything else. I hope somewhen next week...

The GNUInstallDirs module does not handle the /etc case well. When using
this standard module and doing an "install(FILES ... TYPE SYSCONF)" the
result will end up in /usr/etc which is not correct. Set the
CMAKE_INSTALL_SYSCONFDIR variable to the right absolute path instead.
Also introduce a -host and -cross multipackage to test the native and
cross build case.
@jkloetzke jkloetzke merged commit a9d3036 into BobBuildTool:master Dec 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants