Skip to content

Latest commit

 

History

History
460 lines (380 loc) · 21.7 KB

codingGuidelines.md

File metadata and controls

460 lines (380 loc) · 21.7 KB

This document outlines coding guidelines for contributions to the maya-hydra project.

C++ Coding Guidelines

Many of the C++ coding guidelines below are validated and enforced through the use of clang-format which is provided by the LLVM project. Since the adjustments made by clang-format can vary from version to version, we standardize this project on a single clang-format version to ensure consistent results for all contributions made to maya-hydra.

Version Source Code Release
clang-format/LLVM 10.0.0 llvmorg-10.0.0 Tag LLVM 10.0.0

Modern C++

Our project uses C++ 17. Our goal is to develop maya-hydra following modern C++ practices. We follow the C++ Core Guidelines and pay attention to:

  • resource management and the Resource Acquisition is Initialization (RAII) idiom
  • using (vs typedef) keyword
  • virtual, override and final keyword
  • default and delete keywords
  • auto keyword
  • initialization - {}
  • nullptr keyword

Forward Declarations

To reduce compilation coupling, use forward declarations as much as possible, avoiding the inclusion of headers that fully define a type. To encapsulate pointers to objects and preserve the capability to use forward declarations, use the following idiom. It ensures that using the pointer declaration does not require including the full class declaration.

  • Declare the pointer type in a separate header file, with a Fwd suffix, e.g. fvpSelectionFwd.h. This is the file that clients can include when using a pointer of the type in their interface:
//
// Copyright 2023 Autodesk
//
// 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 FVP_SELECTION_FWD_H
#define FVP_SELECTION_FWD_H

#include "flowViewport/flowViewport.h"

#include <memory>

namespace FVP_NS_DEF {

class Selection;

using SelectionPtr      = std::shared_ptr<Selection>;
using SelectionConstPtr = std::shared_ptr<const Selection>;

}

#endif
  • Include this file in the full declaration of the class, e.g. in fvpSelection.h:
//
// Copyright 2023 Autodesk
//
// 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 FVP_SELECTION_H
#define FVP_SELECTION_H

#include "flowViewport/api.h"
#include "flowViewport/selection/fvpSelectionFwd.h"
// [...]
  • Create a trivial .cpp file, e.g. fvpSelectionFwd.cpp, that includes the Fwd header to ensure standalone compilation:
//
// Copyright 2023 Autodesk
//
// 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.
//

// Trivial inclusion to ensure header compiles on its own.
#include "flowViewport/selection/fvpSelectionFwd.h"

Foundation/Critical

License notice

Every file should start with the Apache 2.0 licensing statement:

// 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.

Copyright notice

  • Every file should contain at least one Copyright line at the top, which can be to Autodesk or the individual/company that contributed the code.
  • Multiple copyright lines are allowed, and if a significant new contribution is made to an existing file then an individual or company can append a new line to the copyright section.
  • The year the original contribution is made should be included but there is no requirement to update this every year.
  • There is no requirement that an Autodesk copyright line should be in all files. If an individual or company contributes new files they do not have to add both their name and Autodesk's name.
  • If existing code is being refactored or moved within the repo then the original copyright lines should be maintained. You should only append a new copyright line if significant new changes are added. For example, if some utility code is being moved from a plugin into a common area, and the work involved is only minor name changes or include path updates, then the original copyright should be maintained. In this case, there is no requirement to add a new copyright for the person that handled the refactoring.

#pragma once vs include guard

Do not use #pragma once to avoid files being #include’d multiple times (which can cause duplication of definitions & compilation errors). While it's widely supported, it's a non-standard and non-portable extension. In some cases using #pragma once may include two copies of the same file when they are accessible via multiple different paths.

All code should use include guards instead #pragma once. To ensure uniqueness, include guards must include the path to the included header, with path components converted to uppercase, and separated by an underscore. For example, for file lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaSceneIndex.h:

#ifndef LIB_MAYAHYDRA_HYDRAEXTENSIONS_SCENEINDEX_MHMAYASCENEINDEX_H
#define LIB_MAYAHYDRA_HYDRAEXTENSIONS_SCENEINDEX_MHMAYASCENEINDEX_H
// … declarations …
#endif // LIB_MAYAHYDRA_HYDRAEXTENSIONS_SCENEINDEX_MHMAYASCENEINDEX_H

Never use reserved identifiers, like underscore followed immediately by an uppercase letter or double underscore. For example, the following is illegal:

// file foobar.h:
#ifndef __LIBRARY_FOOBAR_H
#define __LIBRARY_FOOBAR_H
// … declarations …
#endif // __LIBRARY_FOOBAR_H

// file foobar2.h:
#ifndef _LIBRARY_FOOBAR2_H
#define _LIBRARY_FOOBAR2_H
// … declarations …
#endif // _LIBRARY_FOOBAR2_H

Naming (file, type, variable, constant, function, namespace, macro, template parameters, schema names)

General Naming Rules The Hydra for Maya project strives to use "camel case" naming. That is, each word is capitalized, except possibly the first word:

  • UpperCamelCase
  • lowerCamelCase

While underscores in names (_) (e.g., as separator) are not strictly forbidden, they are strongly discouraged. Optimize for readability by selecting names that are clear to others (e.g., people on different teams.) Use names that describe the purpose or intent of the object. Do not worry about saving horizontal space. It is more important to make your code easily understandable by others. Minimize the use of abbreviations that would likely be unknown to someone outside your project (especially acronyms and initialisms). Project-Related Naming When using Maya Hydra in code, the string MayaHydra or mayaHydra should be used, depending on required capitalization. The string maya-hydra should only be used when referring to the Github repository.

Type Names All type names (i.e., classes, structs, type aliases, enums, and type template parameters) should use UpperCamelCase, with no underscores. All top-level classes in the MayaHydra namespace should use a short prefix, to categorize them. Nested classes declared inside another class should not have a prefix. The only currently defined prefix is Mh; others will be added as appropriate. For example:

class MhSceneIndex;
class MhSceneIndex::Data;
enum Roles;

File Names Filenames should be lowerCamelCase and should not include underscores (_) or dashes (-). C++ files should end in .cpp and header files should end in .h. In general, make your filenames as specific as possible. Where file names declare a single class (which should be the majority of cases), the file name should match the class name, except for the case of the leading character. For example:

mhSceneIndex.cpp
mhSceneIndex.h

Variable Names Variables names, including function parameters and data members should use lowerCamelCase, with no underscores. For example:

const MDagPath& dagPath
const MVector& rayDirection
bool* drawRenderPurpose

Class/Struct Data Members Non-static data members of classes/structs are named like ordinary non-member variables with leading "_". For example:

UsdMayaStageNoticeListener _stageNoticeListener;
std::map<UsdTimeCode, MBoundingBox> _boundingBoxCache;

For static data members the leading underscore should be omitted.

static const MTypeId typeId;

Constant Names Variables declared constexpr or const, whose value is fixed for the duration of the program, should be named with a leading "k" followed by UpperCamelCase. For example:

const int kDaysInAWeek = 7;
const int kMyMagicNumber = 42;

Function/Method Names By default, method names should be lowerCamelCase. Exceptions are when a class derives from an existing class, where we adopt the capitalization of the base class, i.e. lowerCamelCase for classes derived from Maya base classes, and UpperCamelCase for classes derived from Hydra base classes. For example:

MString name() const override;
void registerExitCallback();

If a class is declared with multiple inheritance from classes with mixed method names, the default lowerCamelCase should be used, except obviously when overriding methods from a base class.

Namespace Names Namespace names should be UpperCamelCase. Top-level namespace names are based on the project name.

namespace MayaAttrs {}

Use of Pixar Namespace For multiple reasons, some code in the maya-hydra repository places symbols in the Pixar namespace. We intend to move this code to a more appropriate namespace, e.g. the MayaHydra namespace. No new code can add symbols to the Pixar namespace.

When using the Pixar namespace, the PXR_NS macro must be used. This ensures that the maya-hydra code base can be compatible with developers wishing to compile USD code with a Pixar namespace different from the default (pxr).

Enumerator Names Enumerators (for both scoped and unscoped enums) should be named like constants (i.e., kEnumName.)

The enumeration name, StringPolicy is a type and therefore mixed case.

enum class StringPolicy
{
  kStringOptional,
  kStringMustHaveValue
};

Macro Names In general, macros should be avoided (see Modern C++ ). However, if they are absolutely needed, macros should be all capitals, with words separated by underscores.

#define ROUND(x) …
#define PI_ROUNDED 3.0

Schema Names <Not yet defined, proposals are welcome>

Documentation (class, method, variable, comments)

  • Doxygen will be used to generate documentation from Hydra for Maya C++ sources.
  • Doxygen tags must be used to document classes, function parameters, function return values, and thrown exceptions.
  • The Hydra for Maya project does require the use of any Doxygen formatting style ( Doxygen built-in formatting )
  • Comments for users of classes and functions must be written in headers files. Comments in definition files are meant for contributors and maintainers.

Namespaces

In header files (e.g. .h)

  • Required: to use fully qualified namespace names. Global scope using directives are not allowed. Inline code can use using directives in implementations, within a scope, when there is no other choice (e.g. when using macros, which are not namespaced).
// In aFile.h
inline PXR_NS::UsdPrim prim() const
{
    PXR_NAMESPACE_USING_DIRECTIVE
    TF_AXIOM(fItem != nullptr);
    return fItem->prim();
}

In implementation files (e.g. .cpp)

  • Recommended: to use fully qualified namespace names, unless clarity or readability is degraded by use of explicit namespaces, in which case a using directive is acceptable.
  • Recommended: to use the existing namespace style, and not make gratuitous changes. If the file is using explicit namespaces, new code should follow this style, unless the changes are so significant that clarity or readability is degraded. If the file has one or more using directives, new code should follow this style.

Include directive

For source files (.cpp) with an associated header file (.h) that resides in the same directory, it should be #include'd with double quotes and no path. This formatting should be followed regardless of with whether the associated header is public or private. For example:

// In foobar.cpp
#include "foobar.h"

All included public header files from outside and inside the project should be #include’d using angle brackets. For example:

#include <pxr/base/tf/stringUtils.h>
#include <mayaHydraLib/sceneIndex/mayaHydraSceneIndex.h>

Private project’s header files should be #include'd using double quotes, and a relative path. Private headers may live in the same directory or sub-directories, but they should never be included using "." or ".." as part of a relative path. For example:

#include "privateUtils.h"
#include "pvt/helperFunctions.h"

Include order

Headers should be included in the following order, with each section separated by a blank line and files sorted alphabetically:

  1. Related header
  2. All private headers
  3. All public headers from this repository (maya-hydra)
  4. Pixar + USD headers
  5. Autodesk + Maya headers
  6. Other libraries' headers
  7. C++ standard library headers
  8. C system headers
  9. Conditional includes
#include "exportTranslator.h"

#include "private/util.h"
 
#include <mayaHydraLib/adapters/adapterRegistry.h>
#include <mayaHydraLib/adapters/materialNetworkConverter.h>
#include <mayaHydraLib/adapters/mayaAttrs.h>
#include <mayaHydraLib/adapters/renderItemAdapter.h>
 
#include <maya/MFileObject.h>
#include <maya/MGlobal.h>
#include <maya/MSelectionList.h>
#include <maya/MString.h>

#include <string>

#include <ufe/ufe.h>

Cross-platform development

  • Consult the build.md compatibility table to ensure you use the recommended tool (i.e., compiler, operating system, CMake, etc.) versions.
  • Before pull requests (PRs) are considered for integration, they must compile and all tests should pass on all suppported platforms.

Conditional compilation (Maya, USD version)

Maya * MAYA_API_VERSION is the consistent macro to test Maya version (MAYA_APP_VERSION * 10000 + MAJOR_VERSION * 100 + MINOR_VERSION) * MAYA_APP_VERSION is available only since Maya 2019 and is a simple year number, so it is not allowed.

USD * PXR_VERSION is the macro to test USD version (PXR_MAJOR_VERSION * 10000 + PXR_MINOR_VERSION * 100 + PXR_PATCH_VERSION)

Respect the minimum supported version for Maya and USD stated in build.md .

std over boost

Recent extensions to the C++ standard introduce many features previously only found in boost. To avoid introducing additional dependencies, developers should strive to use functionality in the C++ std over boost. If you encounter usage of boost in the code, consider converting this to the equivalent std mechanism. Our library currently has the following boost dependencies:

  • boost::python
  • boost::make_shared (preferable to replace with std::shared_ptr)

Update:

  • boost::filesystem and boost::system are removed. Until the transition to C++17 std::filesystem, ghc::filesystem must be used as an alternative across the project.

Diagnostic Facilities

Developers are encouraged to use TF library diagnostic facilities in Maya USD. Please follow below guideline for picking the correct facility: https://graphics.pixar.com/usd/docs/api/page_tf__diagnostic.html

Coding guidelines for Python

We are adopting the PEP-8 style for Python Code with the following modification:

  • Mixed-case for variable and function names are allowed

Pylint is recommended for automation.

Coding guidelines for CMake

Modern CMake

  1. Target Build and Usage requirements should be very clear.
  • build requirements ( everything that is needed to build the target )
  • usage requirements ( everything that is needed to use this target as a dependency of another target)
  1. Always use target_xxx() and make sure to add the PUBLIC/PRIVATE/INTERFACE keywords as appropriate.
  • target_sources
  • target_compile_definitions
  • target_compile_options
  • target_include_directories
  • target_link_libraries
  • ...

Keyword meanings:

  • PRIVATE: requirement should apply to just this target.
  • PUBLIC: requirement should apply to this target and anything that links to it.
  • INTERFACE: requirement should apply just to things that link to it.
  1. Don't use Macros that affect all targets (e.g add_definitions, link_libraries, include_directories).
  2. Prefer functions over macros whenever reasonable.
  3. Treat warnings as errors.
  4. Use cmake_parse_arguments as the recommended way for parsing the arguments given to the macro or function.
  5. Don't use file(GLOB).
  6. Be explicit by calling set_target_properties when it's appropriate.
  7. Links against Boost or GTest using imported targets rather than variables: e.g Boost::filesystem, Boost::system, GTest::GTest

Compiler features/flags/definitions

  1. Setting or appending compiler flags/definitions via CMAKE_CXX_FLAGS is NOT allowed.
  2. Any front-end flags (e.g. -Wno-xxx, cxx_std_xx) should be added to cmake/compiler_config.cmake
  3. All current targets, as well as newly added targets, must use mayaHydra_compile_config function in order to get the project-wide flags/definitions. These flags/definitions are added privately via target_compile_features, target_compile_options, target_compile_definitions. Individual targets are still allowed to call target_compile_definitions, target_compile_features individually for any additional flags/definitions by providing appropriate PUBLIC/INTERFACE/PRIVATE keywords. For example:
# -----------------------------------------------------------------------------
# compiler configuration
# -----------------------------------------------------------------------------
add_library(${UFE_PYTHON_TARGET_NAME} SHARED)
target_compile_definitions(${UFE_PYTHON_TARGET_NAME}
   PRIVATE
       MFB_PACKAGE_NAME=${UFE_PYTHON_MODULE_NAME}
       MFB_ALT_PACKAGE_NAME=${UFE_PYTHON_MODULE_NAME}
       MFB_PACKAGE_MODULE="${PROJECT_NAME}.${UFE_PYTHON_MODULE_NAME}"
)
mayaHydra_compile_config(${UFE_PYTHON_TARGET_NAME})

Dynamic linking and Run-time Search Path

Use provided mayaUsd_xxx_rpath() utility functions to handle run-time search path for both MacOSX and Linux.

Naming Conventions

  1. CMake commands are case-insensitive. Use lower_case for CMake functions and macros, Use upper_case for CMake variables
# e.g cmake functions
add_subdirectory(schemas)
target_compile_definitions(....)

# e.g cmake variables
${CMAKE_CXX_COMPILER_ID}
${CMAKE_SYSTEM_NAME}
${CMAKE_INSTALL_PREFIX}
  1. Use upper_case for Option names
# e.g for options names
option(BUILD_USDMAYA_SCHEMAS "Build optional schemas." ON)
option(BUILD_TESTS "Build tests." ON)
option(BUILD_MAYAHYDRALIB "Build the Maya-To-Hydra plugin and scene delegate." ON)
  1. Use upper_case for Custom variables
# e.g for options names
set(Boost_USE_DEBUG_PYTHON ON)
 
set(HEADERS
    jobArgs.h
    modelKindProcessor.h
    readJob.h
    writeJob.h
)
 
set(RESOURCES_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/lib/usd/${TARGET_NAME}/resources)
 
set(USDTRANSACTION_PYTHON_LIBRARY_LOCATION ${AL_INSTALL_PREFIX}/lib/python/AL/usd/transaction)
  1. Respect third-party variables ( don't change them )
# e.g boost
set(BOOST_ROOT ${pxr_usd_location})
set(Boost_USE_DEBUG_PYTHON ON)
  1. Avoid adding the optional name in endfunction/endmacro([]).

Although there is no official guideline for Modern CMake practices, the following resources provide ample information on how to adopt these practices: Modern cmake, Effective Modern CMake