Giter VIP home page Giter VIP logo

xrepo-cmake's Introduction

xrepo-cmake

CMake wrapper for Xrepo C and C++ package manager.

Supporting the project

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. 🙏

Introduction

CMake wrapper for Xrepo C and C++ package manager.

This allows using CMake to build your project, while using Xrepo to manage dependent packages. This project is partially inspired by cmake-conan.

Example use cases for this project:

  • Existing CMake projects which want to use Xrepo to manage packages.
  • New projects which have to use CMake, but want to use Xrepo to manage packages.

Note: please use CMake 3.19 or later for reliable package usage in CMake code.

Usage

Apis

xrepo_package

xrepo.cmake provides xrepo_package function to manage packages.

xrepo_package(
    "foo 1.2.3"
    [CONFIGS feature1=true,feature2=false]
    [CONFIGS path/to/script.lua]
    [DEPS]
    [MODE debug|release]
    [ALIAS aliasname]
    [OUTPUT verbose|diagnosis|quiet]
    [DIRECTORY_SCOPE]
)

Some of the function arguments correspond directly to Xrepo command options.

xrepo_package adds package install directory to CMAKE_PREFIX_PATH. So find_package can be used. If CMAKE_MINIMUM_REQUIRED_VERSION >= 3.1, cmake PkgConfig will also search for pkgconfig files under package install directories.

After calling xrepo_package(foo), there are three ways to use foo package:

  1. Call find_package(foo) if package provides cmake config-files.
    • Refer to CMake find_package documentation for more details.
  2. If the package does not provide cmake config files or find modules
    • Following variables can be used to use the pacakge (variable names following cmake find modules standard variable names)
      • foo_INCLUDE_DIRS
      • foo_LIBRARY_DIRS
      • foo_LIBRARIES
      • foo_DEFINITIONS
    • If DIRECTORY_SCOPE is specified, xrepo_package will run following code
      include_directories(${foo_INCLUDE_DIRS})
      link_directories(${foo_LIBRARY_DIRS})
  3. Use xrepo_target_packages. Please refer to following section.

Note CONFIGS path/to/script.lua is for fine control over package configs. For example:

  • Exclude packages on system.
  • Override dependent packages' default configs, e.g. set shared=true.

If DEPS is specified, all dependent libraries will add to CMAKE_PREFIX_PATH, along with include, libraries being included in the four variables.

xrepo_target_packages

Add package includedirs and links/linkdirs to the given target.

xrepo_target_packages(
    target
    [NO_LINK_LIBRARIES]
    [PRIVATE|PUBLIC|INTERFACE]
    package1 package2 ...
)
  • NO_LINK_LIBRARIES
    • In case a package provides multiple libs and user need to select which one to link, pass NO_LINK_LIBRARIES to disable calling target_link_libraries. User should call target_link_libraries to setup correct library linking.
  • PRIVATE|PUBLIC|INTERFACE
    • The default is not specifying propagation control keyword when calling target_include_libraries, target_link_libraries, etc, because there's no default choice on this in CMake.
    • Refer to this Stack Overflow answer for differences.

Use package from official repository

Xrepo official repository: xmake-repo

Here's an example CMakeLists.txt that uses gflags package version 2.2.2 managed by Xrepo.

Integrate xrepo.cmake

cmake_minimum_required(VERSION 3.13.0)

project(foo)

# Download xrepo.cmake if not exists in build directory.
if(NOT EXISTS "${CMAKE_BINARY_DIR}/xrepo.cmake")
    message(STATUS "Downloading xrepo.cmake from https://github.com/xmake-io/xrepo-cmake/")
    # mirror https://cdn.jsdelivr.net/gh/xmake-io/xrepo-cmake@main/xrepo.cmake
    file(DOWNLOAD "https://raw.githubusercontent.com/xmake-io/xrepo-cmake/main/xrepo.cmake"
                  "${CMAKE_BINARY_DIR}/xrepo.cmake"
                  TLS_VERIFY ON)
endif()

# Include xrepo.cmake so we can use xrepo_package function.
include(${CMAKE_BINARY_DIR}/xrepo.cmake)

Add basic packages

xrepo_package("zlib")

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
xrepo_target_packages(example-bin zlib)

Add packages with configs

xrepo_package("gflags 2.2.2" CONFIGS "shared=true,mt=true")

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
xrepo_target_packages(example-bin gflags)

Add packages with cmake modules

xrepo_package("gflags 2.2.2" CONFIGS "shared=true,mt=true")

# `xrepo_package` add gflags install directory to CMAKE_PREFIX_PATH.
# As gflags provides cmake config-files, we can now call `find_package` to find
# gflags package.
find_package(gflags CONFIG COMPONENTS shared)

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
target_link_libraries(example-bin gflags)

Add custom packages

We can also add custom packages in our project.

set(XREPO_XMAKEFILE ${CMAKE_CURRENT_SOURCE_DIR}/packages/xmake.lua)
xrepo_package("myzlib")

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
xrepo_target_packages(example-bin myzlib)

Define myzlib package in packages/xmake.lua

package("myzlib")
    set_homepage("http://www.zlib.net")
    set_description("A Massively Spiffy Yet Delicately Unobtrusive Compression Library")

    set_urls("http://zlib.net/zlib-$(version).tar.gz",
             "https://downloads.sourceforge.net/project/libpng/zlib/$(version)/zlib-$(version).tar.gz")

    add_versions("1.2.10", "8d7e9f698ce48787b6e1c67e6bff79e487303e66077e25cb9784ac8835978017")

    on_install(function (package)
  	-- TODO
    end)

    on_test(function (package)
        assert(package:has_cfuncs("inflate", {includes = "zlib.h"}))
    end)

We can write a custom package in xmake.lua, please refer Define Xrepo package.

Options and variables for xrepo.cmake

Following options can be speicified with cmake -D<var>=<value>. Or use set(var value) in CMakeLists.txt.

  • XMAKE_CMD: string, defaults to empty string
    • Specify path to xmake command. Use this option if xmake is not installed in standard location and can't be detected automatically.
  • XREPO_PACKAGE_VERBOSE: [ON|OFF]
    • Enable verbose output for Xrepo Packages.
  • XREPO_BOOTSTRAP_XMAKE: [ON|OFF]
    • If ON, xrepo.cmake will install xmake if it is not found.
  • XREPO_PACKAGE_DISABLE: [ON|OFF]
    • Set this to ON to disable xrepo_package function.
    • If setting this variable in CMakeLists.txt, please set it before including xrepo.cmake.
  • XREPO_BUILD_PARALLEL_JOBS: [COUNT]
    • Set parallel compilation threads num function.
    • If setting this variable in CMakeLists.txt, please set it before including xrepo.cmake.
  • XMAKE_RELEASE_LATEST: [VERSION]
    • Set xmake version.
    • If setting this variable in CMakeLists.txt, please set it before including xrepo.cmake.

Switching compiler and cross compilation

Following variables controll cross compilation. Note: to specify a different compiler other than the default one on system, platform must be set to "cross".

  • XREPO_TOOLCHAIN: string, defaults to empty string
    • Specify toolchain name. Run xmake show -l toolchains to see available toolchains.
  • XREPO_PLATFORM: string, defaults to empty string
    • Specify platform name. If XREPO_TOOLCHAIN is specified and this is not, XREPO_PLATFORM will be set to cross.
  • XREPO_ARCH: string, defaults to empty string
    • Specify architecture name.
  • XREPO_XMAKEFILE: string, defaults to empty string
    • Specify Xmake script file of Xrepo package.

Use package from 3rd repository

In addition to installing packages from officially maintained repository, Xrepo can also install packages from third-party package managers such as vcpkg/conan/conda/pacman/homebrew/apt/dub/cargo.

For the use of the command line, we can refer to the documentation: Xrepo command usage

We can also use it directly in cmake to install packages from third-party repositories, just add the repository name as a namespace. e.g. vcpkg::zlib, conan::pcre2

Conan

xrepo_package("conan::gflags/2.2.2")

Conda

xrepo_package("conda::gflags 2.2.2")

Vcpkg

xrepo_package("vcpkg::gflags")

Homebrew

xrepo_package("brew::gflags")

How does it work?

xrepo.cmake module basically does the following tasks:

  • Call xrepo install to ensure specific package is installed.
  • Call xrepo fetch to get package information and setup various variables for using the installed package in CMake.

The following section is a short introduction to using Xrepo. It helps to understand how xrepo.cmake works and how to specify some of the options in xrepo_package.

Xrepo workflow

Assmuing Xmake is installed.

Suppose we want to use gflags packages.

First, search for gflags package in Xrepo.

$ xrepo search gflags
The package names:
    gflags:
      -> gflags-v2.2.2: The gflags package contains a C++ library that implements commandline flags processing. (in builtin-repo)

It's already in Xrepo, so we can use it. If it's not in Xrepo, we can create it in self-built repositories.

Let's see what configs are available for the package before using it:

$ xrepo info gflags
...
      -> configs:
         -> mt: Build the multi-threaded gflags library. (default: false)
      -> configs (builtin):
         -> debug: Enable debug symbols. (default: false)
         -> shared: Build shared library. (default: false)
         -> pic: Enable the position independent code. (default: true)
...

Suppose we want to use multi-threaded gflags shared library. We can install the package with following command:

xrepo install --mode=release --configs='mt=true,shared=true' 'gflags 2.2.2'

Only the first call to the above command will compile and install the package. To speed up cmake configuration, xrepo command will only be executed when the package is not installed or xrepo_package parameters have changed.

After package installation, because we are using CMake instead of Xmake, we have to get package installation information by ourself. xrepo fetch command does exactly this:

xrepo fetch --json --mode=release --configs='mt=true,shared=true' 'gflags 2.2.2'

The above command will print out package's include, library directory along with other information. xrepo_package uses these information to setup variables to use the specified package.

For CMake 3.19 and later which has JSON support, xrepo_package parses the JSON output. For previous version of CMake, xrepo_package uses only the --cflags option to get package include directory. Library and cmake module directory are infered from that directory, so it maybe unreliable to detect the correct paths.

xrepo-cmake's People

Contributors

arthapz avatar cyfdecyf avatar fantasy-peak avatar heheda123123 avatar waruqi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

xrepo-cmake's Issues

xrepo_package CONFIGS 如果传递字符串似乎不能很好的工作

Xmake 版本

v2.7.9

操作系统版本和架构

centos7

描述问题

设置 build_only=monitoring;logs;dynamodb, 但是在build 时候 完全获取不到 build_only

package("aws-sdk-cpp")

set_homepage("https://github.com/aws/aws-sdk-cpp.git")
set_description("")

add_urls("https://github.com/aws/aws-sdk-cpp.git")

add_configs("build_only",  {type = "string", description = ""})

add_deps("openssl", {system=false})
add_deps("libcurl", {system=false})
add_deps("zlib", {system=false})

on_install("linux", function (package)
    local configs = {}
    table.insert(configs, "-DCMAKE_BUILD_TYPE=Release")
    table.insert(configs, "-DBUILD_SHARED_LIBS=OFF")
    if package:config("build_only") then
        table.insert(configs, "-DBUILD_ONLY=" .. package:config("build_only"))
    end
    table.insert(configs, "-DENABLE_TESTING=OFF")
    -- table.insert(configs, "-DCMAKE_INSTALL_LIBDIR=lib64")
    table.insert(configs, "-DAUTORUN_UNIT_TESTS=OFF")
    table.insert(configs, "-DCMAKE_CXX_FLAGS=-Wno-error -Wno-error=deprecated-declarations -Wno-deprecated-declarations -Wno-error=deprecated-copy")
    import("package.tools.cmake").install(package, configs)
    -- local l = path.join(package:installdir(), "lib64/*.a")
    -- os.cp(l, package:installdir("lib"))
end)

package_end()

cmakelist-----
set(XREPO_XMAKEFILE ${CMAKE_CURRENT_SOURCE_DIR}/repo/packages/a/aws-sdk-cpp/xmake.lua)
xrepo_package("aws-sdk-cpp 1.11.30" CONFIGS "build_only=monitoring;logs;dynamodb" DEPS "openssl" "libcurl" "zlib")

------------------------------
-- xrepo: /home/fantasy-peak/.local/bin/xmake lua private.xrepo install --includes=/home/fantasy-peak/aws-cloudwatch/repo/packages/a/aws-sdk-cpp/xmake.lua --configs=build_only=monitoring aws-sdk-cpp 1.11.30
xmake f -c --require=n -vD
�[0mchecking for platform ... �[38;2;0;255;0;1mlinux�[0m
�[0mchecking for architecture ... �[38;2;0;255;0;1mx86_64�[0m
�[0mchecking for gcc ... �[38;2;0;255;0;1m/opt/rh/devtoolset-11/root/usr/bin/gcc�[0m
�[0m�[38;2;255;255;0;1mcheckinfo: �[0;2mrunv(zig version) failed(127)�[0m
�[0mchecking for zig ... �[38;2;255;0;0;1mno�[0m
�[0m�[38;2;255;255;0;1mcheckinfo: �[0;2mrunv(zig version) failed(127)�[0m
�[0mchecking for zig ... �[38;2;255;0;0;1mno�[0m
configure
{
    ccache = true
    plat = linux
    arch = x86_64
    host = linux
    ndk_stdcxx = true
    kind = static
    buildir = build
    clean = true
    mode = release
}
�[0m�[38;2;255;0;255;1mxmake require -y -v -D -j 12 --extra={system=false,configs={}} "aws-sdk-cpp 1.11.30"�[0m
�[0mchecking for unzip ... �[38;2;0;255;0;1m/usr/bin/unzip�[0m
...
/home/fantasy-peak/bin/cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DENABLE_TESTING=OFF -DAUTORUN_UNIT_TESTS=OFF "-DCMAKE_CXX_FLAGS=-Wno-error -Wno-error=deprecated-declarations -Wno-deprecated-declarations -Wno-error=deprecated-copy" -DCMAKE_INSTALL_PREFIX=/home/fantasy-peak/.xmake/packages/a/aws-sdk-cpp/1.11.30/4e0143c97b65425b855ad5fd03038b6a -DCMAKE_INSTALL_LIBDIR:PATH=lib -G "Unix Makefiles" -DCMAKE_POSITION_INDEPENDENT_CODE=ON /home/fantasy-peak/.xmake/cache/packages/2306/a/aws-sdk-cpp/1.11.30/source/aws-sdk-cpp

期待的结果

build_only 可以正常传递

工程配置

No response

附加信息和错误日志

No response

Add an option to bootstrap xmake when not found

Currently you use find_package to find xmake, but it would be cool if this script automatically bootstraps a version of xmake in the ${CMAKE_BINARY_DIR} and uses that so the user doesn't have to install it.

windows上包含路径和库路径存在问题

Xmake 版本

2.7.8

操作系统版本和架构

windows 11

描述问题

Rebuild CMake cache
1 > @DELETE "C:/temp/testedxproj/heheda/.edx/cmake/gcc-mgw64-13.1-m32/Debug"
>>>>
2 > C:\tools\mingw64-gcc-13.1-full\bin\cmake.exe -B "C:/temp/testedxproj/heheda/.edx/cmake/gcc-mgw64-13.1-m32/Debug" -S "C:/temp/testedxproj/heheda" -G "CodeBlocks - Ninja" -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_CXX_COMPILER="C:/tools/mingw64-gcc-13.1-full/bin/x86_64-w64-mingw32-g++.exe;-m32 -ftabstop=1" -DCMAKE_C_COMPILER="C:/tools/mingw64-gcc-13.1-full/bin/x86_64-w64-mingw32-gcc.exe;-m32 -ftabstop=1" -DCMAKE_RC_COMPILER="C:/tools/mingw64-gcc-13.1-full/bin/windres.exe" -DCMAKE_RC_FLAGS="-F pe-i386" -DCMAKE_CXX_COMPILER_LAUNCHER="C:/tools/mingw64-gcc-13.1-full/bin/ccache.exe" -DCMAKE_CXX_COMPILER_LAUNCHER="C:/tools/mingw64-gcc-13.1-full/bin/ccache.exe"
-- The C compiler identification is GNU 13.1.0
-- The CXX compiler identification is GNU 13.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/tools/mingw64-gcc-13.1-full/bin/x86_64-w64-mingw32-gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/tools/mingw64-gcc-13.1-full/bin/x86_64-w64-mingw32-g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
statusC:/temp/testedxproj/heheda/.edx/cmake/gcc-mgw64-13.1-m32/Debug
-- Downloading xrepo.cmake from https://github.com/xmake-io/xrepo-cmake/
-- xmake command: C:/Users/Administrator/xmake/xmake.exe
-- xrepo: fetch --json: ON
-- xrepo: CMAKE_C_COMPILER=C:/tools/mingw64-gcc-13.1-full/bin/x86_64-w64-mingw32-gcc.exe CMAKE_CXX_COMPILER=C:/tools/mingw64-gcc-13.1-full/bin/x86_64-w64-mingw32-g++.exe using system default toolchain.
-- xrepo: C:/Users/Administrator/xmake/xmake.exe lua private.xrepo install zlib
-- xrepo: zlib_INCLUDE_DIRS C:\Users\Administrator\AppData\Local\.xmake\packages\z\zlib\v1.2.13\04bf9d8a64824100b68e5c59e579eda6\include
-- xrepo: zlib_LIBRARY_DIRS C:\Users\Administrator\AppData\Local\.xmake\packages\z\zlib\v1.2.13\04bf9d8a64824100b68e5c59e579eda6\lib
-- xrepo: zlib_LIBRARIES zlib
-- xrepo: zlib prepend to CMAKE_PREFIX_PATH: C:/Users/Administrator/AppData/Local/.xmake/packages/z/zlib/v1.2.13/04bf9d8a64824100b68e5c59e579eda6
-- xrepo: target_include_directories(heheda  C:\Users\Administrator\AppData\Local\.xmake\packages\z\zlib\v1.2.13\04bf9d8a64824100b68e5c59e579eda6\include)
CMake Error at .edx/cmake/gcc-mgw64-13.1-m32/Debug/xrepo.cmake:395 (target_include_directories):
  target_include_directories called with invalid arguments
Call Stack (most recent call first):
  CMakeLists.txt:31 (xrepo_target_packages)


-- xrepo: target_link_directories(heheda  C:\Users\Administrator\AppData\Local\.xmake\packages\z\zlib\v1.2.13\04bf9d8a64824100b68e5c59e579eda6\lib)
CMake Error at .edx/cmake/gcc-mgw64-13.1-m32/Debug/xrepo.cmake:399 (target_link_directories):
  target_link_directories called with invalid arguments
Call Stack (most recent call first):
  CMakeLists.txt:31 (xrepo_target_packages)


-- xrepo: target_link_libraries(heheda  zlib)
-- Configuring incomplete, errors occurred!
>>>>
task failed 7.788 s, 0 error(s), 0 warning(s)
>

看提示是给目标设置包含路径和库路径时报错参数错误。这两个路径在我本地是存在的,是不是因为反斜杠转义的问题?

期待的结果

给目标添加路径不出错

工程配置

No response

附加信息和错误日志

No response

如何设置并行编译线程数

你在什么场景下需要该功能?

目前我执行cmake .., xrepo_package 会自动安装依赖, 但是它使用默认24 个线程编译, 我想要设置编译线程数, 该怎么做

描述可能的解决方案

通过配置文件?

描述你认为的候选方案

No response

其他信息

No response

用OpenCV找不到opencv2/opencv.hpp头文件

注:如果是问题报障或者特性请求,请选择报告缺陷特性请求模板,否则一律不回复。

描述讨论详情

请在这描述你需要讨论的话题详情。
cmake ..可以发现opencv,但是make的时候,fatal error: opencv2/opencv.hpp: 没有那个文件或目录

CMakeLists.txt部分:

#指定cmake的最小版本
cmake_minimum_required(VERSION 3.4.1)

project(demo)

set(CMAKE_CXX_FLAGS "-std=c++11")

#Download xrepo.cmake if not exists in build directory.
if(NOT EXISTS "${CMAKE_BINARY_DIR}/xrepo.cmake")
message(STATUS "Downloading xrepo.cmake from https://github.com/xmake-io/xrepo-cmake/")
# mirror https://cdn.jsdelivr.net/gh/xmake-io/xrepo-cmake@main/xrepo.cmake
file(DOWNLOAD "https://raw.githubusercontent.com/xmake-io/xrepo-cmake/main/xrepo.cmake"
"${CMAKE_BINARY_DIR}/xrepo.cmake"
TLS_VERIFY ON)
endif()

include(${CMAKE_BINARY_DIR}/xrepo.cmake)

xrepo_package("spdlog")
xrepo_package("opencv 4.5.4")

在build目录下执行cmake ..的输出如下:

-- xmake command: /usr/bin/xmake
-- xrepo fetch --json: OFF
-- xrepo: spdlog already installed, using cached variables
-- xrepo: spdlog_INCLUDE_DIR /home/XXX/.xmake/packages/s/spdlog/v1.9.2/237d31e048844016b30f5b496e1385d7/include
-- xrepo: spdlog_LINK_DIR /home/XXX/.xmake/packages/s/spdlog/v1.9.2/237d31e048844016b30f5b496e1385d7/lib
-- xrepo: opencv 4.5.4 already installed, using cached variables
-- xrepo: opencv_INCLUDE_DIR /home/XXX/.xmake/packages/o/opencv/4.5.4/e610c461a5844179809cd993282550cb/include
-- xrepo: opencv_LINK_DIR /home/XXX/.xmake/packages/o/opencv/4.5.4/e610c461a5844179809cd993282550cb/lib
-- Configuring done
-- Generating done
-- Build files have been written to: /home/hcq/文档/test/cmakeSift/build

执行make的时候提示:

src/ImgRegistration.h:4:10: fatal error: opencv2/opencv.hpp: 没有那个文件或目录

xrepo_package 为什么不从我本地仓库中查找安装包信息

Xmake Version

2.6.8

Operating System Version and Architecture

centos7

Describe Bug

我执行下面命令增加一个私有仓库 到本地, 但是 xrepo_package 似乎不会从本地仓库中查找软件包, 如果我增加全局仓库它可以工作
xmake repo -a private_repo xxxxxxxgithub/xmake-repo.git

Expected Behavior

可以从本地仓库中查找软件包信息

Project Configuration

No response

Additional Information and Error Logs

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.