This introduces a new versioning mechanism that allows for better automation.
include(CheckIPOSupported)
include(GNUInstallDirs)
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
-set(CVC5_MAJOR 1) # Major component of the version of cvc5.
-set(CVC5_MINOR 0) # Minor component of the version of cvc5.
-set(CVC5_RELEASE 0) # Release component of the version of cvc5.
-
-# Extraversion component of the version of cvc5.
-set(CVC5_EXTRAVERSION "-prerelease")
-
-# Shared library versioning. Increment SOVERSION for every new cvc5 release.
-set(CVC5_SOVERSION 1)
+include(version)
-# Full release string for cvc5.
-if(CVC5_RELEASE)
- set(CVC5_RELEASE_STRING
- "${CVC5_MAJOR}.${CVC5_MINOR}.${CVC5_RELEASE}${CVC5_EXTRAVERSION}")
-else()
- set(CVC5_RELEASE_STRING "${CVC5_MAJOR}.${CVC5_MINOR}${CVC5_EXTRAVERSION}")
-endif()
-
-set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/cvc5ConfigVersion.cmake
- VERSION ${CVC5_RELEASE_STRING}
+ VERSION ${CVC5_VERSION}
COMPATIBILITY ExactVersion
)
string(REPLACE ";" " " CVC5_DEFINITIONS "${CVC5_DEFINITIONS}")
message("")
-print_info("cvc5 ${CVC5_RELEASE_STRING}")
+print_info("cvc5 ${CVC5_VERSION}")
message("")
if(ENABLE_COMP_INC_TRACK)
print_config("Build profile " "${CVC5_BUILD_PROFILE_STRING} (incremental)")
--- /dev/null
+# These are updated when making a release
+set(CVC5_LAST_RELEASE "0.0.0")
+set(CVC5_IS_RELEASE "false")
+
+# These are used in other places in cmake
+# If possible, they are updated by version.cmake
+set(GIT_BUILD "false")
+set(CVC5_IS_RELEASE "false")
+set(CVC5_VERSION "${CVC5_LAST_RELEASE}")
+set(CVC5_FULL_VERSION "${CVC5_LAST_RELEASE}")
+set(CVC5_GIT_INFO "")
+
+# Shared library versioning. Increment SOVERSION for every new cvc5 release.
+set(CVC5_SOVERSION 1)
--- /dev/null
+# These are updated when making a release
+set(CVC5_LAST_RELEASE "{{VERSION}}")
+set(CVC5_IS_RELEASE "{{IS_RELEASE}}")
+
+# These are used in other places in cmake
+# If possible, they are updated by version.cmake
+set(GIT_BUILD "false")
+set(CVC5_IS_RELEASE "false")
+set(CVC5_VERSION "${CVC5_LAST_RELEASE}")
+set(CVC5_FULL_VERSION "${CVC5_LAST_RELEASE}")
+set(CVC5_GIT_INFO "")
+
+# Shared library versioning. Increment SOVERSION for every new cvc5 release.
+set(CVC5_SOVERSION 1)
--- /dev/null
+###############################################################################
+# Top contributors (to current version):
+# Aina Niemetz, Mathias Preiner
+#
+# This file is part of the cvc5 project.
+#
+# Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+# in the top-level source directory and their institutional affiliations.
+# All rights reserved. See the file COPYING in the top-level source
+# directory for licensing information.
+# #############################################################################
+#
+# Responsible to identify the version of this source tree, expose this version
+# information to the rest of cmake and properly update the versioninfo.cpp.
+#
+# Note that the above responsibilities are split among configure and build
+# time. To achieve this, this file is both executed as a part of the regular
+# cmake setup during configure time, but also adds a special target to call
+# itself during build time to always keep versioninfo.cpp updated.
+##
+
+if(CMAKE_SCRIPT_MODE_FILE)
+ # was run as standalone script
+ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+else()
+ # was run within the overall cmake project
+ # add target to update versioninfo.cpp at build time
+ add_custom_target(gen-versioninfo
+ BYPRODUCTS
+ ${CMAKE_BINARY_DIR}/src/base/versioninfo.cpp
+ COMMAND ${CMAKE_COMMAND}
+ -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
+ -DCMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}
+ -P ${PROJECT_SOURCE_DIR}/cmake/version.cmake)
+endif()
+
+# include basic version information
+include(version-base)
+
+# now use git to retrieve additional version information
+find_package(Git)
+if(GIT_FOUND)
+ # git is available
+
+ # call git describe. If result is not 0 this is not a git repository
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} describe --long --tags --match cvc5-*
+ RESULT_VARIABLE GIT_RESULT
+ OUTPUT_VARIABLE GIT_DESCRIBE
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ if(GIT_RESULT EQUAL 0)
+ # it is a git working copy
+
+ set(GIT_BUILD "true")
+ # get current git branch
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
+ RESULT_VARIABLE GIT_RESULT
+ OUTPUT_VARIABLE GIT_BRANCH
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ # result is != 0 if worktree is dirty
+ # note: git diff HEAD shows both staged and unstaged changes.
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} diff HEAD --quiet
+ RESULT_VARIABLE GIT_RESULT
+ )
+ if(GIT_RESULT EQUAL 0)
+ set(GIT_DIRTY_MSG "")
+ else()
+ set(GIT_DIRTY_MSG " with local modifications")
+ endif()
+
+ string(REGEX MATCH "^cvc5-([0-9.]+)-([0-9]+)-g([0-9a-f]+)$" MATCH "${GIT_DESCRIBE}")
+ if(NOT MATCH)
+ message(SEND_ERROR "Unexpected format from 'git describe': '${GIT_DESCRIBE}'")
+ endif()
+ set(GIT_LAST_TAG "${CMAKE_MATCH_1}")
+ set(GIT_COMMITS_SINCE_TAG "${CMAKE_MATCH_2}")
+ set(GIT_COMMIT "${CMAKE_MATCH_3}")
+
+ if(GIT_COMMITS_SINCE_TAG EQUAL "0")
+ # this version *is* a tag
+ set(CVC5_IS_RELEASE "true")
+ set(CVC5_VERSION "${GIT_LAST_TAG}")
+ set(CVC5_FULL_VERSION "${GIT_LAST_TAG}")
+ set(CVC5_GIT_INFO "git tag ${GIT_LAST_TAG} branch ${GIT_BRANCH}${GIT_DIRTY_MSG}")
+ else()
+ # this version is not a tag
+
+ # increment patch part of version
+ string(REGEX MATCHALL "[0-9]+" VERSION_LIST "${GIT_LAST_TAG}")
+ list(LENGTH VERSION_LIST VERSION_LIST_LENGTH)
+ # append .0 until we have a patch part
+ while(VERSION_LIST_LENGTH LESS "3")
+ list(APPEND VERSION_LIST "0")
+ list(LENGTH VERSION_LIST VERSION_LIST_LENGTH)
+ endwhile()
+ # increment patch part
+ list(POP_BACK VERSION_LIST VERSION_LAST_NUMBER)
+ math(EXPR VERSION_LAST_NUMBER "${VERSION_LAST_NUMBER} + 1")
+ list(APPEND VERSION_LIST ${VERSION_LAST_NUMBER})
+ string(JOIN "." GIT_LAST_TAG ${VERSION_LIST})
+
+ set(CVC5_VERSION "${GIT_LAST_TAG}-dev")
+ set(CVC5_FULL_VERSION "${GIT_LAST_TAG}-dev.${GIT_COMMITS_SINCE_TAG}.${GIT_COMMIT}")
+ set(CVC5_GIT_INFO "git ${GIT_COMMIT} on branch ${GIT_BRANCH}${GIT_DIRTY_MSG}")
+ endif()
+ endif()
+endif()
+
+# actually configure versioninfo.cpp
+configure_file(
+ ${PROJECT_SOURCE_DIR}/src/base/versioninfo.cpp.in ${CMAKE_BINARY_DIR}/src/base/versioninfo.cpp)
--- /dev/null
+#!/usr/bin/env python3
+
+import argparse
+import collections
+import logging
+import os
+import re
+import subprocess
+import sys
+
+args = None
+
+
+def exec(cmd):
+ """Execute given command"""
+ return subprocess.check_output(cmd).decode().strip()
+
+
+def parse_options():
+ """Handle command line options"""
+ ap = argparse.ArgumentParser(description='Make a new release')
+ ap.add_argument('bump',
+ choices=['major', 'minor', 'patch'],
+ help='which version part to bump')
+ ap.add_argument('-v',
+ '--verbose',
+ action='store_true',
+ help='be more verbose')
+ global args
+ args = ap.parse_args()
+
+ logging.basicConfig(format='[%(levelname)s] %(message)s')
+ if args.verbose:
+ logging.getLogger().setLevel(level=logging.DEBUG)
+ else:
+ logging.getLogger().setLevel(level=logging.INFO)
+
+
+def identify_next_version():
+ """Figure out the new version number"""
+ try:
+ curversion = exec(['git', 'describe', '--tags', '--match', 'cvc5-*'])
+ except:
+ logging.error('git describe was unable to produce a proper version')
+ sys.exit(1)
+ logging.debug('git version info: {}'.format(curversion))
+
+ re_release = re.compile('^cvc5-(\d+)\.(\d+)\.(\d+)')
+ m = re_release.match(curversion)
+ if m:
+ major, minor, patch = map(int, m.groups())
+ if args.bump == 'major':
+ major += 1
+ minor = 0
+ patch = 0
+ elif args.bump == 'minor':
+ minor += 1
+ patch = 0
+ elif args.bump == 'patch':
+ patch += 1
+ version = "{}.{}.{}".format(major, minor, patch)
+ logging.debug('target version: {}'.format(version))
+ return version
+
+ logging.error(
+ "Did not understand current git version: '{}'".format(curversion))
+ sys.exit(1)
+
+
+def generate_cmake_version_file(version, is_release):
+ """Update the cmake version file"""
+ filename = os.path.join(os.path.dirname(os.path.dirname(__file__)),
+ 'cmake/version-base.cmake')
+ tpl = open(filename + '.template').read()
+ tpl = tpl.replace('{{VERSION}}', version)
+ tpl = tpl.replace('{{IS_RELEASE}}', 'true' if is_release else 'false')
+ open(filename, 'w').write(tpl)
+
+
+def make_release_commit(version):
+ """Make the release commit"""
+ tagname = 'cvc5-{}'.format(version)
+ exec(['git', 'add', 'cmake/version-base.cmake'])
+ exec(['git', 'commit', '-m', 'Bump version to {}'.format(version)])
+ exec(['git', 'tag', tagname])
+ return tagname
+
+
+def make_post_release_commit(version):
+ """Make the post-release commit"""
+ exec(['git', 'add', 'cmake/version-base.cmake'])
+ exec(['git', 'commit', '-m', 'Start post-release for {}'.format(version)])
+ return exec(['git', 'rev-parse', 'HEAD'])
+
+
+if __name__ == '__main__':
+ parse_options()
+
+ # Compute next version
+ version = identify_next_version()
+
+ # release commit
+ logging.info('Performing release commit')
+ generate_cmake_version_file(version, True)
+ tagname = make_release_commit(version)
+
+ # post-release commit
+ logging.info('Performing post-release commit')
+ generate_cmake_version_file(version, False)
+ postcommit = make_post_release_commit(version)
+
+ # Show commits and ask user to push
+ print('Please check the following commits carefully:')
+ subprocess.call(['git', 'show', tagname])
+ subprocess.call(['git', 'show', postcommit])
+
+ print(
+ 'If you are sure you want to push this release, use the following command:'
+ )
+ print('\tgit push --tags origin master')
# add_dependencies() is necessary for cmake versions before 3.21
add_dependencies(cvc5-obj cvc5base cvc5context)
# Add libcvc5 dependencies for generated sources.
-add_dependencies(cvc5-obj gen-expr gen-gitinfo gen-options gen-tags gen-theory)
+add_dependencies(cvc5-obj gen-expr gen-versioninfo gen-options gen-tags gen-theory)
# Link the shared library
add_library(cvc5-shared SHARED)
target_link_libraries(cvc5jni PRIVATE ${JNI_LIBRARIES})
target_link_libraries(cvc5jni PRIVATE cvc5-shared)
-set(CVC5_JAR "cvc5-${CVC5_MAJOR}.${CVC5_MINOR}.${CVC5_RELEASE}.jar")
+set(CVC5_JAR "cvc5-${CVC5_VERSION}.jar")
# create cvc5.jar file
add_jar(cvc5jar
SOURCES
${JAVA_FILES}
- VERSION ${CVC5_MAJOR}.${CVC5_MINOR}.${CVC5_RELEASE}
+ VERSION ${CVC5_VERSION}
OUTPUT_NAME cvc5
)
set_target_properties(cvc5jar PROPERTIES SOURCES "${JAVA_FILES}")
from setuptools import setup
-CVC5_VERSION='${CVC5_MAJOR}.${CVC5_MINOR}.${CVC5_RELEASE}'
+CVC5_VERSION='${CVC5_VERSION}'
setup(name='pycvc5',
version=CVC5_VERSION,
# The build system configuration.
##
-# Extract info from Git for git_versioninfo.cpp
-# Note: GitInfo.cmake generates git_versioninfo.cpp.
-find_package(Git)
-configure_file(GitInfo.cmake.in GitInfo.cmake @ONLY)
-add_custom_target(gen-gitinfo
- BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/git_versioninfo.cpp
- COMMAND ${CMAKE_COMMAND} -DGIT_FOUND=${GIT_FOUND} -P GitInfo.cmake)
-
-
# Generate cvc5config.h header
configure_file(cvc5config.h.in cvc5config.h)
modal_exception.h
output.cpp
output.h
- ${CMAKE_CURRENT_BINARY_DIR}/git_versioninfo.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.cpp
)
set_source_files_properties(
- ${CMAKE_CURRENT_BINARY_DIR}/git_versioninfo.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.cpp
PROPERTIES GENERATED TRUE
)
add_library(cvc5base OBJECT ${LIBBASE_SOURCES})
set_target_properties(cvc5base PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_compile_definitions(cvc5base PRIVATE -D__BUILDING_CVC5LIB)
-add_dependencies(cvc5base gen-gitinfo gen-tags)
+add_dependencies(cvc5base gen-versioninfo gen-tags)
+++ /dev/null
-###############################################################################
-# Top contributors (to current version):
-# Aina Niemetz, Mathias Preiner
-#
-# This file is part of the cvc5 project.
-#
-# Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
-# in the top-level source directory and their institutional affiliations.
-# All rights reserved. See the file COPYING in the top-level source
-# directory for licensing information.
-# #############################################################################
-##
-
-set(GIT_BUILD "false")
-set(GIT_IS_DIRTY "false")
-set(GIT_SHA1 "")
-set(GIT_BRANCH "")
-
-if(GIT_FOUND)
- # Get current git branch, result is != 0 if this is not a git repository
- execute_process(
- COMMAND @GIT_EXECUTABLE@ -C @PROJECT_SOURCE_DIR@ rev-parse --abbrev-ref HEAD
- RESULT_VARIABLE GIT_RESULT
- OUTPUT_VARIABLE GIT_BRANCH
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
- if("${GIT_RESULT}" STREQUAL "0")
- set(GIT_BUILD "true")
- # Extract sha1 of HEAD
- execute_process(
- COMMAND @GIT_EXECUTABLE@ -C @PROJECT_SOURCE_DIR@ rev-parse HEAD
- OUTPUT_VARIABLE GIT_SHA1
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
- # Result is != 0 if worktree is dirty
- # Note: git diff HEAD shows both staged and unstaged changes.
- execute_process(
- COMMAND @GIT_EXECUTABLE@ -C @PROJECT_SOURCE_DIR@ diff HEAD --quiet
- RESULT_VARIABLE GIT_RESULT
- )
- if(NOT "${GIT_RESULT}" STREQUAL "0")
- set(GIT_IS_DIRTY "true")
- endif()
- endif()
-endif()
-
-configure_file(
- @CMAKE_CURRENT_SOURCE_DIR@/git_versioninfo.cpp.in git_versioninfo.cpp)
string Configuration::getPackageName() { return CVC5_PACKAGE_NAME; }
-string Configuration::getVersionString() { return CVC5_RELEASE_STRING; }
-
-unsigned Configuration::getVersionMajor() { return CVC5_MAJOR; }
-
-unsigned Configuration::getVersionMinor() { return CVC5_MINOR; }
-
-unsigned Configuration::getVersionRelease() { return CVC5_RELEASE; }
-
-std::string Configuration::getVersionExtra() { return CVC5_EXTRAVERSION; }
+string Configuration::getVersionString() { return CVC5_FULL_VERSION; }
std::string Configuration::copyright() {
std::stringstream ss;
std::string Configuration::about() {
std::stringstream ss;
- ss << "This is cvc5 version " << CVC5_RELEASE_STRING;
+ ss << "This is cvc5 version " << getVersionString();
if (Configuration::isGitBuild()) {
- ss << " [" << Configuration::getGitId() << "]";
+ ss << " [" << Configuration::getGitInfo() << "]";
}
ss << "\ncompiled with " << Configuration::getCompiler()
<< "\non " << Configuration::getCompiledDateTime() << "\n\n";
}
bool Configuration::isGitBuild() {
- return IS_GIT_BUILD;
-}
-
-const char* Configuration::getGitBranchName() {
- return GIT_BRANCH_NAME;
-}
-
-const char* Configuration::getGitCommit() {
- return GIT_COMMIT;
+ return GIT_BUILD;
}
-bool Configuration::hasGitModifications() {
- return GIT_HAS_MODIFICATIONS;
-}
-
-std::string Configuration::getGitId() {
- if(! isGitBuild()) {
- return "";
- }
-
- const char* branchName = getGitBranchName();
- if(*branchName == '\0') {
- branchName = "-";
- }
-
- stringstream ss;
- ss << "git " << branchName << " " << string(getGitCommit()).substr(0, 8)
- << (::cvc5::Configuration::hasGitModifications() ? " (with modifications)"
- : "");
- return ss.str();
+std::string Configuration::getGitInfo() {
+ return CVC5_GIT_INFO;
}
std::string Configuration::getCompiler() {
Configuration();
// these constants are filled in by the build system
- static const bool IS_GIT_BUILD;
- static const char* const GIT_BRANCH_NAME;
- static const char* const GIT_COMMIT;
- static const bool GIT_HAS_MODIFICATIONS;
+ static const bool GIT_BUILD;
+ static const bool CVC5_IS_RELEASE;
+ static const char* const CVC5_VERSION;
+ static const char* const CVC5_FULL_VERSION;
+ static const char* const CVC5_GIT_INFO;
public:
static std::string getVersionString();
- static unsigned getVersionMajor();
-
- static unsigned getVersionMinor();
-
- static unsigned getVersionRelease();
-
- static std::string getVersionExtra();
-
static std::string copyright();
static std::string about();
static bool isTraceTag(const std::string& tag);
static bool isGitBuild();
- static const char* getGitBranchName();
- static const char* getGitCommit();
- static bool hasGitModifications();
- static std::string getGitId();
+ static std::string getGitInfo();
static std::string getCompiler();
static std::string getCompiledDateTime();
#ifndef CVC5__BASE__CVC5CONFIG_H
#define CVC5__BASE__CVC5CONFIG_H
-/* Major component of the version of cvc5. */
-#define CVC5_MAJOR @CVC5_MAJOR@
-
-/* Minor component of the version of cvc5. */
-#define CVC5_MINOR @CVC5_MINOR@
-
-/* Release component of the version of cvc5. */
-#define CVC5_RELEASE @CVC5_RELEASE@
-
-/* Extraversion component of the version of cvc5. */
-#define CVC5_EXTRAVERSION "@CVC5_EXTRAVERSION@"
-
-/* Full release string for cvc5. */
-#define CVC5_RELEASE_STRING "@CVC5_RELEASE_STRING@"
-
/* Full name of this package. */
#define CVC5_PACKAGE_NAME "@CVC5_PACKAGE_NAME@"
+++ /dev/null
-/******************************************************************************
- * Top contributors (to current version):
- * Aina Niemetz
- *
- * This file is part of the cvc5 project.
- *
- * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
- * in the top-level source directory and their institutional affiliations.
- * All rights reserved. See the file COPYING in the top-level source
- * directory for licensing information.
- * ****************************************************************************
- *
- * Compile version info from git.
- */
-
-#include "base/configuration.h"
-const bool ::cvc5::Configuration::IS_GIT_BUILD = @GIT_BUILD@;
-const char* const ::cvc5::Configuration::GIT_BRANCH_NAME = "@GIT_BRANCH@";
-const char* const ::cvc5::Configuration::GIT_COMMIT = "@GIT_SHA1@";
-const bool ::cvc5::Configuration::GIT_HAS_MODIFICATIONS = @GIT_IS_DIRTY@;
--- /dev/null
+/******************************************************************************
+ * Top contributors (to current version):
+ * Aina Niemetz
+ *
+ * This file is part of the cvc5 project.
+ *
+ * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+ * in the top-level source directory and their institutional affiliations.
+ * All rights reserved. See the file COPYING in the top-level source
+ * directory for licensing information.
+ * ****************************************************************************
+ *
+ * Compile version info from git.
+ */
+
+#include "base/configuration.h"
+
+const bool ::cvc5::Configuration::GIT_BUILD = @GIT_BUILD@;
+const bool ::cvc5::Configuration::CVC5_IS_RELEASE = @CVC5_IS_RELEASE@;
+const char* const ::cvc5::Configuration::CVC5_VERSION = "@CVC5_VERSION@";
+const char* const ::cvc5::Configuration::CVC5_FULL_VERSION = "@CVC5_FULL_VERSION@";
+const char* const ::cvc5::Configuration::CVC5_GIT_INFO = "@CVC5_GIT_INFO@";
\ No newline at end of file
<< Configuration::getVersionString();
if (Configuration::isGitBuild())
{
- CVC5Message() << " [" << Configuration::getGitId() << "]";
+ CVC5Message() << " [" << Configuration::getGitInfo() << "]";
}
CVC5Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
<< " assertions:"
std::cout << Configuration::about() << std::endl;
print_config("version", Configuration::getVersionString());
-
if (Configuration::isGitBuild())
{
- const char* branchName = Configuration::getGitBranchName();
- if (*branchName == '\0')
- {
- branchName = "-";
- }
- std::stringstream ss;
- ss << "git [" << branchName << " "
- << std::string(Configuration::getGitCommit()).substr(0, 8)
- << (Configuration::hasGitModifications() ? " (with modifications)" : "")
- << "]";
- print_config("scm", ss.str());
+ print_config("scm", Configuration::getGitInfo());
}
else
{
std::cout << std::endl;
std::stringstream ss;
- ss << Configuration::getVersionMajor() << "."
- << Configuration::getVersionMinor() << "."
- << Configuration::getVersionRelease();
+ ss << Configuration::getVersionString();
print_config("library", ss.str());
std::cout << std::endl;
{
// just test that the functions exist
Configuration::getVersionString();
- Configuration::getVersionMajor();
- Configuration::getVersionMinor();
- Configuration::getVersionRelease();
}
TEST_F(TestUtilBlackConfiguration, about)