본문으로 건너뛰기
Abseil Code Review · 1/79

Abseil 개요 — Google이 std를 보완한 이유

· Hawk · 5분 읽기

한 줄 요약: Abseil은 Google이 사내 수억 줄의 C++ 코드를 떠받치기 위해 만든 라이브러리이고, std의 빈자리를 메우거나 std보다 빠른 구현을 제공하는 두 축으로 굴러간다.

#어떤 문제를 푸는가

C++ 표준은 천천히 움직인다. 위원회가 합의에 도달하는 데 수년이 걸리고, 컴파일러가 지원하는 데 또 수년이 걸린다. 그동안 production 코드베이스는 멈춰 있을 수 없다. Google은 사내에서 표준에 들어갈 만한 기능을 먼저 만들어 쓰고, 표준화가 확정되면 std로 옮겨가는 식으로 움직였다. Abseil은 그 사내 결과물을 외부에 공개한 것이다.

세 가지 빈자리가 있다.

  1. 표준에 아직 없는 기능 — C++17 이전의 string_view, optional, C++20 이전의 span 같은 polyfill.
  2. 표준에 있지만 느리거나 어색한 구현unordered_map의 노드 기반 설계 대신 Swiss table 기반 flat_hash_map.
  3. 표준에 들어갈 가능성이 없는 도메인absl::Status, absl::Time, absl::Flag 같이 Google의 production 패턴에 특화된 도구.

Abseil은 이 셋을 한 우산 아래 묶어 제공한다.

#무엇이 들어 있는가

13개의 sub-library가 있다. 굵직한 것만 꼽으면 다음과 같다.

영역헤더대표 타입/함수
기반absl/base/*ABSL_PREDICT_TRUE, ABSL_ATTRIBUTE_*, raw_logging
에러 처리absl/status/*absl::Status, absl::StatusOr<T>
문자열absl/strings/*absl::StrCat, absl::StrSplit, absl::string_view
컨테이너absl/container/*absl::flat_hash_map, absl::btree_map, absl::InlinedVector
동기화absl/synchronization/*absl::Mutex, absl::Notification
시간absl/time/*absl::Time, absl::Duration, absl::CivilDay
수치/타입absl/numeric/*, absl/types/*absl::int128, absl::optional, absl::variant
로깅absl/log/*LOG(INFO), CHECK, VLOG
플래그absl/flags/*ABSL_FLAG, absl::ParseCommandLine

#짧은 맛보기

#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/container/flat_hash_map.h"
#include "absl/time/clock.h"
absl::StatusOr<int> ParseAge(absl::string_view s) {
int v;
if (!absl::SimpleAtoi(s, &v)) {
return absl::InvalidArgumentError(
absl::StrCat("not a number: ", s));
}
if (v < 0 || v > 200) {
return absl::OutOfRangeError(absl::StrCat("age out of range: ", v));
}
return v;
}
void Demo() {
absl::flat_hash_map<std::string, int> ages;
absl::Time start = absl::Now();
if (auto age = ParseAge("42"); age.ok()) {
ages["alice"] = *age;
}
absl::Duration elapsed = absl::Now() - start;
LOG(INFO) << "took " << elapsed;
}

여기서 보이는 패턴은 시리즈 전반에 반복된다. exception을 던지지 않고 StatusOr로 결과를 감싼다. 문자열 합치기는 StrCat으로 단일 할당에 끝낸다. 시간은 Duration이라는 강타입으로 다룬다.

#왜 또 다른 라이브러리인가

흔히 받는 질문이다. 답은 표준 위원회의 속도Google의 production 요구 사이의 간극에 있다.

  • 표준은 std::unordered_map을 바꿀 수 없다. ABI 안정성 때문에 노드 기반 구현이 박제되어 있다. Google은 더 빠른 해시맵이 필요했고, 새 타입으로 만드는 수밖에 없었다.
  • 표준의 std::optional<T&>은 끝내 합의되지 않았다. Abseil은 자체 absl::optional을 가지고 있지만 reference에 대한 합의는 마찬가지로 보류 중이다.
  • exception을 쓰지 않는 코드베이스에서 에러를 반환하는 표준 방식은 빈약하다. std::error_code는 너무 가볍고, exception은 금지. 그 자리에 absl::Status가 들어간다.

#std와의 관계

Abseil은 std를 대체하지 않는다. 보완한다. 같은 코드베이스에서 둘이 공존하는 것이 정상이다.

// std와 absl을 섞어 쓰는 일상적 코드
std::vector<absl::string_view> tokens =
absl::StrSplit(line, ',', absl::SkipEmpty());
std::unique_ptr<Worker> w = std::make_unique<Worker>();
absl::StatusOr<int> n = w->Process(tokens);

선택의 일반 원칙은 다음과 같다.

상황권장
std 버전이 충분히 빠르고 표준에 있음std (std::optional on C++17+)
std 버전이 느리거나 어색함absl (absl::flat_hash_map)
표준에 없음absl (absl::Status, absl::Time)
컴파일러 지원 폴리필표준 도달 후 std로 마이그레이션

#두 가지 릴리스 모드

Abseil은 두 모드로 배포된다.

  • HEAD — main 브랜치를 직접 추적. Google 사내가 이 모델로 산다. “Live at Head” 철학.
  • LTS — 1년에 두 번 정도 끊는 long-term snapshot. 외부 패키지 매니저(vcpkg, Conan)는 LTS만 다룬다.

이 둘의 차이는 1-04에서 자세히 다룬다. 일단은 “사내는 HEAD, 사외는 LTS”라고 기억해두면 충분하다.

#ABI 정책

Abseil의 ABI 정책은 한 줄로 요약된다.

같은 빌드 단위 안에서만 ABI 호환을 보장한다.

Abseil로 빌드한 두 정적 라이브러리를 다른 플래그로 컴파일해서 같은 실행 파일에 링크하면 동작이 깨질 수 있다. ODR violation을 막기 위해 inline namespace로 빌드 옵션을 인코딩하는 메커니즘이 들어 있다. 자세한 내용은 Part 1-05: Versioning & ABI 호환성에서 다룬다.

이 정책은 단일 실행 파일을 통째로 빌드하는 Google 사내 monorepo 모델에 최적화되어 있다. 외부 사용자에게는 약간의 함정이 있다.

#빌드 시스템

Abseil은 Bazel-first다. CMake는 second-class지만 LTS 릴리스에 함께 제공된다.

# Bazel — WORKSPACE 또는 MODULE.bazel
http_archive(
name = "com_google_absl",
sha256 = "...",
strip_prefix = "abseil-cpp-20240722.0",
urls = ["https://github.com/abseil/abseil-cpp/releases/download/20240722.0/abseil-cpp-20240722.0.tar.gz"],
)
# CMake — FetchContent
include(FetchContent)
FetchContent_Declare(
absl
GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
GIT_TAG 20240722.0
)
FetchContent_MakeAvailable(absl)
target_link_libraries(my_app PRIVATE absl::strings absl::status)

Bazel과 CMake 양쪽의 차이는 1-03에서 자세히 다룬다.

#이 시리즈를 읽는 법

세 가지 동선이 있다.

  1. production 코드를 읽고 리뷰하는 사람 — Part 3 (Status) → Part 4 (Strings) → Part 5 (Container) 순서. 가장 자주 마주치는 세 영역.
  2. 시스템 코드를 쓰는 사람 — Part 2 (Base · Meta · Memory)를 먼저. macro와 attribute로 portability를 확보하는 도구가 모여 있다.
  3. 마이그레이션 담당자 — Part 13 (Code Review Patterns)을 먼저 훑고, 필요한 모듈만 깊이 들어가는 방식.

이 시리즈는 사용법이 아니라 왜 이 모양인가에 비중을 둔다. cppreference처럼 API를 나열하지 않고, code review에서 “이걸 쓰면 안 되는 이유”가 무엇인지를 함께 본다.

#정리

  • Abseil은 Google 사내 라이브러리의 오픈소스 부분 집합이고, std의 빈자리를 메우거나 std보다 빠른 구현을 제공한다.
  • 13개 sub-library로 구성되며 Status, Strings, Container가 가장 자주 마주친다.
  • std와 공존하는 것이 정상이고, 선택 기준은 “표준에 있는가, 충분히 빠른가” 두 가지로 단순화할 수 있다.
  • HEAD와 LTS 두 모드가 있고, ABI 호환은 단일 빌드 단위 안에서만 보장된다.
  • Bazel이 first-class, CMake가 second-class.

#다음 편

Part 1-02에서는 Abseil의 설계 철학을 본다. “std 호환 + 추가 기능”이라는 슬로건이 실제로는 어떤 트레이드오프 위에 서 있는지, header-only로 만들 수 없는 이유가 무엇인지 다룬다.

#관련 항목

Abseil Code Review · 2 of 79

  1. 1 Abseil Code Review — Google production-grade C++ 라이브러리 분석
  2. 2 Abseil 개요 — Google이 std를 보완한 이유
  3. 3 Abseil 설계 철학 — std 호환과 추가 기능의 균형
  4. 4 Abseil 빌드와 의존성 — Bazel vs CMake
  5. 5 Abseil LTS vs HEAD 릴리스 모델 분석
  6. 6 Abseil Versioning과 ABI 호환성 정책
  7. 7 Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
  8. 8 Abseil ABSL_PREDICT_TRUE/FALSE — branch hint
  9. 9 absl::LogSeverity — 로그 레벨 타입
  10. 10 Abseil type_traits — negation·conjunction·void_t
  11. 11 Abseil Conformance·Policy 분석
  12. 12 Abseil Memory utilities 분석
  13. 13 Abseil raw_logging — heap-free 로깅
  14. 14 Abseil thread_annotations — clang TSA 통합
  15. 15 absl::Status — exception-free error handling
  16. 16 absl::StatusOr<T> — 값 또는 에러
  17. 17 absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
  18. 18 absl::Status payload — 구조화된 에러 컨텍스트
  19. 19 absl::Status ↔ exception 변환 패턴
  20. 20 absl::string_view — non-owning 문자열 참조
  21. 21 absl::string_view 함정 — dangling·c_str·임시 객체
  22. 22 absl::StrCat — 가변 인자 문자열 연결과 AlphaNum
  23. 23 absl::StrSplit — Delimiter·Predicate·컨테이너 변환
  24. 24 absl::StrJoin — 컨테이너 결합과 Formatter
  25. 25 absl::StrFormat — type-safe printf·FormatSpec
  26. 26 Abseil ASCII 함수 — locale-free 분류·대소문자 변환
  27. 27 Abseil Escape — CEscape·HexEscape·Base64
  28. 28 absl::flat_hash_map — Swiss Table 기반 hash map
  29. 29 absl::flat_hash_set — set 버전 Swiss Table
  30. 30 absl::node_hash_map — stable pointer가 필요할 때
  31. 31 absl::btree_map — sorted·cache-friendly B-tree
  32. 32 absl::FixedArray — 런타임 크기 stack 배열
  33. 33 absl::InlinedVector — small buffer optimization
  34. 34 Abseil Swiss Table internals — control byte·SIMD probing
  35. 35 absl::Mutex — reader-writer·fairness·deadlock 검출
  36. 36 absl::Mutex Conditional Critical Section — Await로 cv 없애기
  37. 37 absl::Notification — once-only signal
  38. 38 absl::BlockingCounter·Barrier — 다중 thread 조율
  39. 39 absl::Mutex annotations — clang thread-safety로 race를 컴파일 타임에
  40. 40 absl::Time·Duration 분석 — 단단한 type
  41. 41 absl::Time Format·Parse
  42. 42 absl::CivilTime 분석
  43. 43 absl::time_zone 분석
  44. 44 absl::Time mocking — 테스트 친화 시간
  45. 45 absl::BitGen — 모던 난수 생성기
  46. 46 Abseil Random Distributions — Uniform·Exponential
  47. 47 Abseil Mocking Random — 테스트 결정성
  48. 48 Abseil Random Seeding·Entropy
  49. 49 absl::int128·uint128 분석
  50. 50 absl::bits — popcount·countl_zero
  51. 51 absl::optional vs std::optional
  52. 52 absl::variant 분석
  53. 53 absl::span 분석
  54. 54 absl::any 분석
  55. 55 absl::compare — three-way 비교
  56. 56 Abseil utility — apply·in_place
  57. 57 Abseil AbslHashValue 분석
  58. 58 Abseil HashState chaining
  59. 59 Abseil Custom hashable 구현
  60. 60 Abseil LOG·VLOG·CHECK 분석
  61. 61 Abseil LogSink 분석
  62. 62 Abseil LogEntry·structured logging
  63. 63 Abseil Stack trace·failure_signal_handler
  64. 64 ABSL_FLAG 정의 분석
  65. 65 Abseil ParseCommandLine 동작
  66. 66 Abseil Flag introspection·validation
  67. 67 Google 스타일의 Abseil 사용 패턴
  68. 68 Abseil 자주 보는 anti-pattern
  69. 69 std → absl 마이그레이션 전략
  70. 70 absl::Cleanup — 함수 종료 시 실행 보장
  71. 71 Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
  72. 72 absl::function_ref와 any_invocable — 함수 객체 전달의 두 축
  73. 73 absl::bind_front와 Overload — 함수 객체 보조 도구
  74. 74 absl::Cord — 분산 시스템용 대용량 문자열
  75. 75 absl::from_chars·SimpleAtoi — 빠른 숫자 변환
  76. 76 absl::Cord vs std::string — 선택 기준과 메모리 프로파일
  77. 77 absl::GetStackTrace와 Symbolize — crash 시 readable stack
  78. 78 absl::ComputeCrc32c — 하드웨어 가속 체크섬
  79. 79 absl::PeriodicSampler — 적응형 샘플링·jitter 회피