Gregor modules

87
Modules Doug Gregor, Apple Wednesday, November 7, 12

description

 

Transcript of Gregor modules

Page 1: Gregor modules

ModulesDoug Gregor, Apple

Wednesday, November 7, 12

Page 2: Gregor modules

Roadmap

• The fundamental brokenness of headers

• A module system for the C family

• Building better tools

Wednesday, November 7, 12

Page 3: Gregor modules

On the Fundamental Brokenness of Headers

Wednesday, November 7, 12

Page 4: Gregor modules

#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model

Wednesday, November 7, 12

Page 5: Gregor modules

#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 6: Gregor modules

#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 7: Gregor modules

// from stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model

Wednesday, November 7, 12

Page 8: Gregor modules

// from stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

int main() { printf(“Hello, world!\n”);}

Problems with the Model

• Fragility

• Performance

Wednesday, November 7, 12

Page 9: Gregor modules

#define FILE “MyFile.txt”#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Header Fragility

Wednesday, November 7, 12

Page 10: Gregor modules

#define FILE “MyFile.txt”#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Header Fragility// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 11: Gregor modules

#define FILE “MyFile.txt”#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Header Fragility// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 12: Gregor modules

// from stdio.h

typedef struct { ...} “MyFile.txt”;

int printf(const char*, ...);int fprintf(“MyFile.txt” *, const char*, ...);int remove(const char*);

// on and on...

int main() { printf(“Hello, world!\n”);}

Header Fragility

Wednesday, November 7, 12

Page 13: Gregor modules

Conventional Workarounds

Wednesday, November 7, 12

Page 14: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

Wednesday, November 7, 12

Page 15: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

• LLVM_CLANG_INCLUDE_GUARD_H

Wednesday, November 7, 12

Page 16: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

• LLVM_CLANG_INCLUDE_GUARD_H

• template<class _Tp>const _Tp& min(const _Tp &__a, const _Tp &__b);

Wednesday, November 7, 12

Page 17: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

• LLVM_CLANG_INCLUDE_GUARD_H

• template<class _Tp>const _Tp& min(const _Tp &__a, const _Tp &__b);

• #include <windows.h>#undef min // because #define NOMINMAX#undef max // doesn’t always work

Wednesday, November 7, 12

Page 18: Gregor modules

How Big is a Source File?

Wednesday, November 7, 12

Page 19: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Wednesday, November 7, 12

Page 20: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

Wednesday, November 7, 12

Page 21: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

#include <iostream>

int main() { std::cout << “Hello, world!” << std::endl;}

Wednesday, November 7, 12

Page 22: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

#include <iostream>

int main() { std::cout << “Hello, world!” << std::endl;}

Wednesday, November 7, 12

Page 23: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

#include <iostream>

int main() { std::cout << “Hello, world!” << std::endl;}

Wednesday, November 7, 12

Page 24: Gregor modules

Inherently Non-Scalable

• M headers with N source files

• M x N build cost

• C++ templates exacerbate the problem

• Precompiled headers are a terrible solution

Wednesday, November 7, 12

Page 25: Gregor modules

A Module System for the C Family

Wednesday, November 7, 12

Page 26: Gregor modules

What Is a Module?

• A module is a package describing a library

• Interface of the library (API)

• Implementation of the library

Wednesday, November 7, 12

Page 27: Gregor modules

Module Imports

• ‘import’ makes the API of the named module available

import std;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 28: Gregor modules

Module Imports

• ‘import’ makes the API of the named module available

import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 29: Gregor modules

Module Imports

• ‘import’ makes the API of the named module available

import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 30: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

Wednesday, November 7, 12

Page 31: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

#define FILE “MyFile.txt”import std;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 32: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

#define FILE “MyFile.txt”import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 33: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

#define FILE “MyFile.txt”import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 34: Gregor modules

Selective Import// std module

// stdio submodule

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

// stdlib submodule

void abort(void);int rand(void);

// on and on...

Wednesday, November 7, 12

Page 35: Gregor modules

Selective Importimport std.stdio;

int main() { printf(“Hello, World!\n”);}

// std module

// stdio submodule

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

// stdlib submodule

void abort(void);int rand(void);

// on and on...

Wednesday, November 7, 12

Page 36: Gregor modules

Selective Importimport std.stdio;

int main() { printf(“Hello, World!\n”);}

// std module

// stdio submodule

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

// stdlib submodule

void abort(void);int rand(void);

// on and on...

Wednesday, November 7, 12

Page 37: Gregor modules

What Does import Import?

• Functions, variables, types, templates, macros, etc.

• Only public API -- everything else can be hidden.

• No special namespace mechanism.

Wednesday, November 7, 12

Page 38: Gregor modules

Writing a ModuleFuturistic Version

Wednesday, November 7, 12

Page 39: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

Wednesday, November 7, 12

Page 40: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

• Specify module name in source file

Wednesday, November 7, 12

Page 41: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

• Specify module name in source file

• Public access describes API

Wednesday, November 7, 12

Page 42: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

• Specify module name in source file

• Public access describes API

• No headers!

Wednesday, November 7, 12

Page 43: Gregor modules

Problems With This Future

• Transitioning existing header-based libraries

• Interoperability with compilers that don’t implement modules

• Requires tools that understand modules

Wednesday, November 7, 12

Page 44: Gregor modules

Writing a ModuleTransitional Version

Wednesday, November 7, 12

Page 45: Gregor modules

Embracing Headers

• Build modules directly from the headers

• Headers remain “the truth”

• Good for interoperability

• Doesn’t change the programmer model

Wednesday, November 7, 12

Page 46: Gregor modules

Module Maps// /usr/include/module.map

module std { module stdio { header “stdio.h” } module stdlib { header “stdlib.h” } module math { header “math.h” }}

• module defines a named (sub)module

• header includes the contents of the named header in the current (sub)module

Wednesday, November 7, 12

Page 47: Gregor modules

Umbrella Headers

• An umbrella header includes all of the headers in its directory

// clang/include/clang/module.map

module ClangAST { umbrella header “AST/AST.h” module * { }}

Wednesday, November 7, 12

Page 48: Gregor modules

Umbrella Headers

• An umbrella header includes all of the headers in its directory

• Wildcard submodules (module *) create a submodule for each included header

• AST/Decl.h -> ClangAST.Decl

• AST/Expr.h -> ClangAST.Expr

// clang/include/clang/module.map

module ClangAST { umbrella header “AST/AST.h” module * { }}

Wednesday, November 7, 12

Page 49: Gregor modules

Module Map Features

Wednesday, November 7, 12

Page 50: Gregor modules

Module Map Features

• Umbrella directoriesmodule LLVMADT { umbrella “llvm/ADT” module * { export * }}

Wednesday, November 7, 12

Page 51: Gregor modules

Module Map Features

• Umbrella directories

• Submodule requirements

module LLVMADT { umbrella “llvm/ADT” module * { export * }}

module _Builtin { module avx { requires avx header “avxintrin.h” }}

Wednesday, November 7, 12

Page 52: Gregor modules

Module Map Features

• Umbrella directories

• Submodule requirements

• Excluded headers

module LLVMADT { umbrella “llvm/ADT” module * { export * }}

module _Builtin { module avx { requires avx header “avxintrin.h” }}

module std { exclude header “assert.h”}

Wednesday, November 7, 12

Page 53: Gregor modules

Compilation Modelimport std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 54: Gregor modules

Compilation Model

1. Find a module map for the named module

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 55: Gregor modules

Compilation Model

1. Find a module map for the named module

2. Spawn a separate instance of the compiler:

• Parse the headers in the module map

• Write the module file

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 56: Gregor modules

Compilation Model

1. Find a module map for the named module

2. Spawn a separate instance of the compiler:

• Parse the headers in the module map

• Write the module file

3. Load the module file at the ‘import’ declaration

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 57: Gregor modules

Compilation Model

1. Find a module map for the named module

2. Spawn a separate instance of the compiler:

• Parse the headers in the module map

• Write the module file

3. Load the module file at the ‘import’ declaration

4. Cache module file for later re-use

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 58: Gregor modules

Adopting Modules: Libraries

• Eliminate non-modular behavior:

• Multiply-defined structs, functions, macros, must be consolidated

• Headers should import what they depend on

• Write module maps covering the library

Wednesday, November 7, 12

Page 59: Gregor modules

Adopting Modules: Users

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 60: Gregor modules

Adopting Modules: Users

• “Simply” rewrite each #include as an import

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 61: Gregor modules

Translating #include to import

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 62: Gregor modules

Translating #include to import

• Use module maps to determine (sub)module corresponding to an #include’d header

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 63: Gregor modules

Translating #include to import

• Use module maps to determine (sub)module corresponding to an #include’d header

• Optional Fix-Its, tooling to finalize the rewrite

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 64: Gregor modules

Translating #include to import

• Use module maps to determine (sub)module corresponding to an #include’d header

• Optional Fix-Its, tooling to finalize the rewrite

• Enabling modules is transparent to the user

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 65: Gregor modules

Building Better Tools(For the Future)

Wednesday, November 7, 12

Page 66: Gregor modules

Compilation Performance

• Algorithmic improvement for parsing time

• Module headers parsed once, cached

• M x N M + N

• Benefits for all source-based tools

Wednesday, November 7, 12

Page 67: Gregor modules

Automatic Linking

• Drastically simplifies use of a library

// clang/include/clang/module.map

module ClangAST { umbrella header “AST/AST.h” module * { } link “-lclangAST”}

Wednesday, November 7, 12

Page 68: Gregor modules

Automatic Import

• Forgotten #include terrible diagnostic

int main() { std::vector<int> v;}

Wednesday, November 7, 12

Page 69: Gregor modules

Automatic Import

• Forgotten #include terrible diagnostic

• vector.cpp:2:6: error: ‘vector‘ template is not available std::vector<int> v; ^note: import ‘std.vector‘ to use ‘std::vector’

int main() { std::vector<int> v;}

Wednesday, November 7, 12

Page 70: Gregor modules

Debugging Flow

Wednesday, November 7, 12

Page 71: Gregor modules

Debugging Flow

foo.cpp<iostream>

Wednesday, November 7, 12

Page 72: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

Wednesday, November 7, 12

Page 73: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

Wednesday, November 7, 12

Page 74: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB

Wednesday, November 7, 12

Page 75: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

Wednesday, November 7, 12

Page 76: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

• Round-trip through DWARF is lossy

• Only ‘used’ types, functions available

• Inline functions, template definitions lost

Wednesday, November 7, 12

Page 77: Gregor modules

Redundant Debug Info

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

Wednesday, November 7, 12

Page 78: Gregor modules

Redundant Debug Info

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs

bar.o

object code

foo DWARF

iostream DWARF

Wednesday, November 7, 12

Page 79: Gregor modules

Redundant Debug Info

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs

bar.o

object code

foo DWARF

iostream DWARF

Wednesday, November 7, 12

Page 80: Gregor modules

Debugging with Modules

foo.cpp<iostream> Clang ASTs foo DWARF

foo.o

object code

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs foo DWARF

bar.o

object code

Wednesday, November 7, 12

Page 81: Gregor modules

Debugging with Modules

foo.cpp<iostream> Clang ASTs foo DWARF

foo.o

object code

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs foo DWARF

bar.o

object code

std.iostream module

Wednesday, November 7, 12

Page 82: Gregor modules

Debugging with Modules

• Improved build performance

• Compiler emits less DWARF

• Linker de-duplicates less DWARF

Wednesday, November 7, 12

Page 83: Gregor modules

Debugging with Modules

• Improved build performance

• Compiler emits less DWARF

• Linker de-duplicates less DWARF

• Improved debugging experience

• Perfect AST fidelity in debugger

• Debugger doesn’t need to search DWARF

Wednesday, November 7, 12

Page 84: Gregor modules

Modules Summary

Wednesday, November 7, 12

Page 85: Gregor modules

Modules Summary

• Modules are a huge potential win for C(++)

• Compile/build time improvements

• Fix various preprocessor problems

• Far better tool experience

Wednesday, November 7, 12

Page 86: Gregor modules

Modules Summary

• Modules are a huge potential win for C(++)

• Compile/build time improvements

• Fix various preprocessor problems

• Far better tool experience

• Design enables smooth transition path

Wednesday, November 7, 12

Page 87: Gregor modules

Modules Summary

• Modules are a huge potential win for C(++)

• Compile/build time improvements

• Fix various preprocessor problems

• Far better tool experience

• Design enables smooth transition path

• Clang implementation underway

Wednesday, November 7, 12