Compile-time size assertions for MuJoCo basic types

PiperOrigin-RevId: 919107499
Change-Id: I07fcba4f33c77a2a1e68528dba6d399af94d0220
This commit is contained in:
Yuval Tassa
2026-05-21 09:54:33 -07:00
committed by Copybara-Service
parent 585be6cee5
commit 15d27b363f
7 changed files with 145 additions and 54 deletions
+1
View File
@@ -108,6 +108,7 @@ include(MujocoMacOS)
include(MujocoDependencies)
set(MUJOCO_HEADERS
include/mujoco/mjassert.h
include/mujoco/mjdata.h
include/mujoco/mjexport.h
include/mujoco/mjmacro.h
+6
View File
@@ -80,6 +80,12 @@ General
- MJX: Removed the deprecated ``nconmax`` argument from ``mjx.make_data`` and ``mjx.put_data`` in favor of
``naconmax``.
- Maybe-breaking: Added `mjassert.h
<https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjassert.h>`__, a new header containing
compile-time assertions that verify the sizes of MuJoCo's public types for ABI stability. This is a first step
towards replacing ``int`` with strongly-typed enums in the public API. If these assertions fail on your compiler or
platform, please report the issue on GitHub.
Version 3.8.1 (May 11, 2026)
----------------------------
+2
View File
@@ -184,6 +184,8 @@ links below, to make this documentation self-contained.
code.
`mjsan.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjsan.h>`__
Definitions required when building with sanitizer instrumentation.
`mjassert.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjassert.h>`__
Compile-time size assertions verifying MuJoCo ABI stability across C and C++ compilers.
.. _inVersion:
+133
View File
@@ -0,0 +1,133 @@
// Copyright 2026 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_MJASSERT_H_
#define MUJOCO_MJASSERT_H_
#include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjplugin.h>
#include <mujoco/mjrender.h>
#include <mujoco/mjspec.h>
#include <mujoco/mjthread.h>
#include <mujoco/mjtype.h>
#include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h>
#if defined(__cplusplus)
#define MJ_ASSERT_SIZE(type, size) \
static_assert(sizeof(type) == (size), #type " must be " #size " bytes for MuJoCo ABI stability")
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define MJ_ASSERT_SIZE(type, size) \
_Static_assert(sizeof(type) == (size), #type " must be " #size " bytes for MuJoCo ABI stability")
#else
#define MJ_ASSERT_SIZE(type, size) \
typedef char mj_assert_##type[sizeof(type) == (size) ? 1 : -1]
#endif
// mjtnum.h
MJ_ASSERT_SIZE(mjtByte, 1);
MJ_ASSERT_SIZE(mjtSize, 8);
#if !defined(mjUSESINGLE)
MJ_ASSERT_SIZE(mjtNum, 8);
#else
MJ_ASSERT_SIZE(mjtNum, 4);
#endif
// mjmodel.h
MJ_ASSERT_SIZE(mjtDisableBit, 4);
MJ_ASSERT_SIZE(mjtEnableBit, 4);
MJ_ASSERT_SIZE(mjtJoint, 4);
MJ_ASSERT_SIZE(mjtGeom, 4);
MJ_ASSERT_SIZE(mjtProjection, 4);
MJ_ASSERT_SIZE(mjtCamLight, 4);
MJ_ASSERT_SIZE(mjtLightType, 4);
MJ_ASSERT_SIZE(mjtTexture, 4);
MJ_ASSERT_SIZE(mjtTextureRole, 4);
MJ_ASSERT_SIZE(mjtColorSpace, 4);
MJ_ASSERT_SIZE(mjtIntegrator, 4);
MJ_ASSERT_SIZE(mjtCone, 4);
MJ_ASSERT_SIZE(mjtJacobian, 4);
MJ_ASSERT_SIZE(mjtSolver, 4);
MJ_ASSERT_SIZE(mjtEq, 4);
MJ_ASSERT_SIZE(mjtWrap, 4);
MJ_ASSERT_SIZE(mjtTrn, 4);
MJ_ASSERT_SIZE(mjtDyn, 4);
MJ_ASSERT_SIZE(mjtGain, 4);
MJ_ASSERT_SIZE(mjtBias, 4);
MJ_ASSERT_SIZE(mjtObj, 4);
MJ_ASSERT_SIZE(mjtSensor, 4);
MJ_ASSERT_SIZE(mjtStage, 4);
MJ_ASSERT_SIZE(mjtDataType, 4);
MJ_ASSERT_SIZE(mjtConDataField, 4);
MJ_ASSERT_SIZE(mjtRayDataField, 4);
MJ_ASSERT_SIZE(mjtCamOutBit, 4);
MJ_ASSERT_SIZE(mjtSameFrame, 4);
MJ_ASSERT_SIZE(mjtSleepPolicy, 4);
MJ_ASSERT_SIZE(mjtLRMode, 4);
MJ_ASSERT_SIZE(mjtFlexSelf, 4);
MJ_ASSERT_SIZE(mjtSDFType, 4);
// mjdata.h
MJ_ASSERT_SIZE(mjtState, 4);
MJ_ASSERT_SIZE(mjtConstraint, 4);
MJ_ASSERT_SIZE(mjtConstraintState, 4);
MJ_ASSERT_SIZE(mjtWarning, 4);
MJ_ASSERT_SIZE(mjtTimer, 4);
MJ_ASSERT_SIZE(mjtSleepState, 4);
// mjspec.h
MJ_ASSERT_SIZE(mjtGeomInertia, 4);
MJ_ASSERT_SIZE(mjtMeshInertia, 4);
MJ_ASSERT_SIZE(mjtMeshBuiltin, 4);
MJ_ASSERT_SIZE(mjtBuiltin, 4);
MJ_ASSERT_SIZE(mjtMark, 4);
MJ_ASSERT_SIZE(mjtLimited, 4);
MJ_ASSERT_SIZE(mjtAlignFree, 4);
MJ_ASSERT_SIZE(mjtInertiaFromGeom, 4);
MJ_ASSERT_SIZE(mjtOrientation, 4);
// mjvisualize.h
MJ_ASSERT_SIZE(mjtCatBit, 4);
MJ_ASSERT_SIZE(mjtMouse, 4);
MJ_ASSERT_SIZE(mjtPertBit, 4);
MJ_ASSERT_SIZE(mjtCamera, 4);
MJ_ASSERT_SIZE(mjtLabel, 4);
MJ_ASSERT_SIZE(mjtFrame, 4);
MJ_ASSERT_SIZE(mjtVisFlag, 4);
MJ_ASSERT_SIZE(mjtRndFlag, 4);
MJ_ASSERT_SIZE(mjtStereo, 4);
// mjrender.h
MJ_ASSERT_SIZE(mjtGridPos, 4);
MJ_ASSERT_SIZE(mjtFramebuffer, 4);
MJ_ASSERT_SIZE(mjtDepthMap, 4);
MJ_ASSERT_SIZE(mjtFontScale, 4);
MJ_ASSERT_SIZE(mjtFont, 4);
// mjui.h
MJ_ASSERT_SIZE(mjtButton, 4);
MJ_ASSERT_SIZE(mjtEvent, 4);
MJ_ASSERT_SIZE(mjtItem, 4);
MJ_ASSERT_SIZE(mjtSection, 4);
// mjthread.h
MJ_ASSERT_SIZE(mjtTaskStatus, 4);
// mjplugin.h
MJ_ASSERT_SIZE(mjtPluginCapabilityBit, 4);
#undef MJ_ASSERT_SIZE
#endif // MUJOCO_MJASSERT_H_
+1
View File
@@ -35,6 +35,7 @@
#include <mujoco/mjtype.h>
#include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mjassert.h>
// this is a C-API
#ifdef __cplusplus
+1 -54
View File
@@ -21,12 +21,7 @@
#include <vector>
#include <gtest/gtest.h>
#include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjrender.h>
#include <mujoco/mjtype.h>
#include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mujoco.h>
#include <mujoco/mjxmacro.h>
#include "test/fixture.h"
@@ -58,59 +53,11 @@ void CheckAddressOrdering(
using HeaderTest = MujocoTest;
TEST_F(HeaderTest, IntsHave4Bytes) {
EXPECT_EQ(4, sizeof(int));
}
TEST_F(HeaderTest, IntsHaveAtLeast31Bits) {
int shift_left_30 = 1 << 30;
EXPECT_GT(shift_left_30, 0);
}
TEST_F(HeaderTest, EnumsAreInts) {
EXPECT_EQ(sizeof(mjtDisableBit), sizeof(int));
EXPECT_EQ(sizeof(mjtEnableBit), sizeof(int));
EXPECT_EQ(sizeof(mjtJoint), sizeof(int));
EXPECT_EQ(sizeof(mjtGeom), sizeof(int));
EXPECT_EQ(sizeof(mjtCamLight), sizeof(int));
EXPECT_EQ(sizeof(mjtTexture), sizeof(int));
EXPECT_EQ(sizeof(mjtIntegrator), sizeof(int));
EXPECT_EQ(sizeof(mjtCone), sizeof(int));
EXPECT_EQ(sizeof(mjtJacobian), sizeof(int));
EXPECT_EQ(sizeof(mjtSolver), sizeof(int));
EXPECT_EQ(sizeof(mjtEq), sizeof(int));
EXPECT_EQ(sizeof(mjtWrap), sizeof(int));
EXPECT_EQ(sizeof(mjtTrn), sizeof(int));
EXPECT_EQ(sizeof(mjtDyn), sizeof(int));
EXPECT_EQ(sizeof(mjtGain), sizeof(int));
EXPECT_EQ(sizeof(mjtBias), sizeof(int));
EXPECT_EQ(sizeof(mjtObj), sizeof(int));
EXPECT_EQ(sizeof(mjtConstraint), sizeof(int));
EXPECT_EQ(sizeof(mjtConstraintState), sizeof(int));
EXPECT_EQ(sizeof(mjtSensor), sizeof(int));
EXPECT_EQ(sizeof(mjtStage), sizeof(int));
EXPECT_EQ(sizeof(mjtDataType), sizeof(int));
EXPECT_EQ(sizeof(mjtLRMode), sizeof(int));
EXPECT_EQ(sizeof(mjtWarning), sizeof(int));
EXPECT_EQ(sizeof(mjtTimer), sizeof(int));
EXPECT_EQ(sizeof(mjtGridPos), sizeof(int));
EXPECT_EQ(sizeof(mjtFramebuffer), sizeof(int));
EXPECT_EQ(sizeof(mjtFontScale), sizeof(int));
EXPECT_EQ(sizeof(mjtFont), sizeof(int));
EXPECT_EQ(sizeof(mjtButton), sizeof(int));
EXPECT_EQ(sizeof(mjtEvent), sizeof(int));
EXPECT_EQ(sizeof(mjtItem), sizeof(int));
EXPECT_EQ(sizeof(mjtCatBit), sizeof(int));
EXPECT_EQ(sizeof(mjtMouse), sizeof(int));
EXPECT_EQ(sizeof(mjtPertBit), sizeof(int));
EXPECT_EQ(sizeof(mjtCamera), sizeof(int));
EXPECT_EQ(sizeof(mjtLabel), sizeof(int));
EXPECT_EQ(sizeof(mjtFrame), sizeof(int));
EXPECT_EQ(sizeof(mjtVisFlag), sizeof(int));
EXPECT_EQ(sizeof(mjtRndFlag), sizeof(int));
EXPECT_EQ(sizeof(mjtStereo), sizeof(int));
}
TEST_F(HeaderTest, MjOptionFields) {
mjOption o;
std::vector<std::pair<const void*, const char*>> fields;
+1
View File
@@ -24,6 +24,7 @@ public static class MujocoLib {
// ----------------------------------Constants----------------------------------
public const bool THIRD_PARTY_MUJOCO_MJASSERT_H_ = true;
public const bool THIRD_PARTY_MUJOCO_MJDATA_H_ = true;
public const bool THIRD_PARTY_MUJOCO_MJEXPORT_H_ = true;
public const bool MUJOCO_HELPER_DLL_LOCAL = true;