mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Add clang-tidy and builds with assertions/memory sanitizers for libGD.js (#7051)
Only show in developer changelog
This commit is contained in:
@@ -176,6 +176,7 @@ jobs:
|
||||
|
||||
# Build the WebAssembly library only (so that it's cached on a S3 and easy to re-use).
|
||||
build-gdevelop_js-wasm-only:
|
||||
resource_class: medium+ # Compilation time decrease linearly with the number of CPUs, but not linking (so "large" does not speedup total build time).
|
||||
docker:
|
||||
- image: cimg/node:16.13
|
||||
|
||||
@@ -232,10 +233,83 @@ jobs:
|
||||
name: Deploy to S3 (latest)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
# Build the WebAssembly library with clang-tidy and memory sanitizers.
|
||||
build-gdevelop_js-debug-sanitizers-and-extra-checks:
|
||||
resource_class: xlarge # Total time decrease linearly with the number of CPUs.
|
||||
docker:
|
||||
- image: cimg/node:16.13
|
||||
|
||||
working_directory: ~/GDevelop
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- aws-cli/setup
|
||||
|
||||
# System dependencies (for Emscripten)
|
||||
- run:
|
||||
name: Install dependencies for Emscripten
|
||||
command: sudo apt-get update && sudo apt install cmake
|
||||
|
||||
- run:
|
||||
name: Install dependencies for clang-tidy v19
|
||||
command: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 19 && sudo apt install clang-tidy-19
|
||||
|
||||
- run:
|
||||
name: Install Python3 dependencies for Emscripten
|
||||
command: sudo apt install python-is-python3 python3-distutils -y
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
|
||||
|
||||
# GDevelop.js dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- gdevelop.js-linux-nodejs-dependencies-
|
||||
|
||||
- run:
|
||||
name: Install GDevelop.js dependencies and build it
|
||||
command: cd GDevelop.js && npm install && cd ..
|
||||
|
||||
# Build GDevelop.js
|
||||
- run:
|
||||
name: Build GDevelop.js ('debug-sanitizers' variant)
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build -- --variant=debug-sanitizers
|
||||
|
||||
- run:
|
||||
name: Run clang-tidy
|
||||
command: cd GDevelop.js && npm run lint
|
||||
|
||||
- run:
|
||||
name: Run tests
|
||||
command: cd GDevelop.js && npm run test -- --maxWorkers=4
|
||||
|
||||
# Upload artifacts (CircleCI)
|
||||
- store_artifacts:
|
||||
path: Binaries/embuild/GDevelop.js
|
||||
|
||||
# Upload artifacts (AWS)
|
||||
- run:
|
||||
name: Deploy to S3 (specific commit)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/variant/debug-sanitizers/commit/$(git rev-parse HEAD)/
|
||||
|
||||
workflows:
|
||||
builds:
|
||||
gdevelop_js-wasm:
|
||||
jobs:
|
||||
- build-gdevelop_js-wasm-only
|
||||
gdevelop_js-wasm-extra-checks:
|
||||
jobs:
|
||||
- build-gdevelop_js-debug-sanitizers-and-extra-checks:
|
||||
# Extra checks are resource intensive so don't all run them.
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /experimental-build.*/
|
||||
builds:
|
||||
jobs:
|
||||
- build-macos:
|
||||
filters:
|
||||
branches:
|
||||
|
4
.clang-tidy
Normal file
4
.clang-tidy
Normal file
@@ -0,0 +1,4 @@
|
||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,-cppcoreguidelines-explicit-virtual-functions,-cppcoreguidelines-avoid-const-or-ref-data-members,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-owning-memory,-cppcoreguidelines-virtual-class-destructor,-clang-analyzer-optin.performance.Padding,-cppcoreguidelines-narrowing-conversions'
|
||||
WarningsAsErrors: 'cppcoreguidelines-pro-type-member-init, clang-analyzer-optin.cplusplus.UninitializedObject'
|
||||
HeaderFilterRegex: '.*'
|
||||
FormatStyle: none
|
@@ -69,12 +69,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# uninitialized variables or other hard to debug bugs.
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wuninitialized
|
||||
-Wconditional-uninitialized
|
||||
-Wno-unknown-warning-option
|
||||
-Wno-reorder-ctor
|
||||
-Wno-reorder
|
||||
-Wno-unused-parameter
|
||||
-Wno-pessimizing-move
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-variable # Not a good style, but not a risk
|
||||
-Wno-unused-private-field
|
||||
-Wno-ignored-qualifiers # Not a risk
|
||||
-Wno-sign-compare # Not a big risk
|
||||
|
||||
# Make as much warnings considered as errors as possible (only one for now).
|
||||
-Werror=return-stack-address
|
||||
|
@@ -72,8 +72,6 @@ class GD_CORE_API WhileEvent : public gd::BaseEvent {
|
||||
///< de/activate infinite loop warning when the
|
||||
///< user create the event
|
||||
|
||||
mutable unsigned int whileConditionsHeight;
|
||||
|
||||
int GetConditionsHeight() const;
|
||||
int GetActionsHeight() const;
|
||||
int GetWhileConditionsHeight() const;
|
||||
|
@@ -36,8 +36,8 @@ struct GD_CORE_API ExpressionParserLocation {
|
||||
|
||||
private:
|
||||
bool isValid;
|
||||
size_t startPosition;
|
||||
size_t endPosition;
|
||||
size_t startPosition = 0;
|
||||
size_t endPosition = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -37,8 +37,7 @@ BehaviorMetadata::BehaviorMetadata(
|
||||
className(className_),
|
||||
iconFilename(icon24x24),
|
||||
instance(instance_),
|
||||
sharedDatasInstance(sharedDatasInstance_),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
|
||||
sharedDatasInstance(sharedDatasInstance_) {
|
||||
SetFullName(gd::String(fullname_));
|
||||
SetDescription(gd::String(description_));
|
||||
SetDefaultName(gd::String(defaultName_));
|
||||
|
@@ -394,7 +394,7 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
bool isPrivate = false;
|
||||
bool isHidden = false;
|
||||
gd::String openFullEditorLabel;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility = QuickCustomization::Visibility::Default;
|
||||
|
||||
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
|
||||
std::shared_ptr<gd::Behavior> instance;
|
||||
|
@@ -185,10 +185,10 @@ class GD_CORE_API EffectMetadata {
|
||||
gd::String fullname;
|
||||
gd::String description;
|
||||
std::vector<gd::String> includeFiles;
|
||||
bool isMarkedAsNotWorkingForObjects;
|
||||
bool isMarkedAsOnlyWorkingFor2D;
|
||||
bool isMarkedAsOnlyWorkingFor3D;
|
||||
bool isMarkedAsUnique;
|
||||
bool isMarkedAsNotWorkingForObjects = false;
|
||||
bool isMarkedAsOnlyWorkingFor2D = false;
|
||||
bool isMarkedAsOnlyWorkingFor3D = false;
|
||||
bool isMarkedAsUnique = false;
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
};
|
||||
|
||||
|
@@ -19,7 +19,8 @@ EventMetadata::EventMetadata(const gd::String &name_,
|
||||
: fullname(fullname_),
|
||||
description(description_),
|
||||
group(group_),
|
||||
instance(instance_) {
|
||||
instance(instance_),
|
||||
hasCustomCodeGenerator(false) {
|
||||
ClearCodeGenerationAndPreprocessing();
|
||||
if (instance) instance->SetType(name_);
|
||||
}
|
||||
|
@@ -83,7 +83,7 @@ class GD_CORE_API EventMetadata {
|
||||
gd::String group;
|
||||
|
||||
std::shared_ptr<gd::BaseEvent> instance;
|
||||
bool hasCustomCodeGenerator;
|
||||
bool hasCustomCodeGenerator = false;
|
||||
std::function<gd::String(gd::BaseEvent& event,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context)>
|
||||
|
@@ -288,8 +288,8 @@ class GD_CORE_API MetadataProvider {
|
||||
static EffectMetadata badEffectMetadata;
|
||||
static gd::InstructionMetadata badInstructionMetadata;
|
||||
static gd::ExpressionMetadata badExpressionMetadata;
|
||||
int useless; // Useless member to avoid emscripten "must have a positive
|
||||
// integer typeid pointer" runtime error.
|
||||
int useless = 0; // Useless member to avoid emscripten "must have a positive
|
||||
// integer typeid pointer" runtime error.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -40,8 +40,7 @@ class Object;
|
||||
class ObjectConfiguration;
|
||||
} // namespace gd
|
||||
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
|
||||
CreateFunPtr;
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()> CreateFunPtr;
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -51,25 +50,25 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API CompilationInfo {
|
||||
public:
|
||||
CompilationInfo() : informationCompleted(false){};
|
||||
virtual ~CompilationInfo(){};
|
||||
CompilationInfo() {};
|
||||
virtual ~CompilationInfo() {};
|
||||
|
||||
bool informationCompleted;
|
||||
bool informationCompleted = false;
|
||||
|
||||
bool runtimeOnly; ///< True if the extension was compiled for a runtime use
|
||||
///< only
|
||||
bool runtimeOnly = false; ///< True if the extension was compiled for a
|
||||
///< runtime use only
|
||||
|
||||
#if defined(__GNUC__)
|
||||
int gccMajorVersion;
|
||||
int gccMinorVersion;
|
||||
int gccPatchLevel;
|
||||
int gccMajorVersion = 0;
|
||||
int gccMinorVersion = 0;
|
||||
int gccPatchLevel = 0;
|
||||
#endif
|
||||
|
||||
int sfmlMajorVersion;
|
||||
int sfmlMinorVersion;
|
||||
int sfmlMajorVersion = 0;
|
||||
int sfmlMinorVersion = 0;
|
||||
|
||||
gd::String gdCoreVersion;
|
||||
int sizeOfpInt;
|
||||
int sizeOfpInt = 0;
|
||||
};
|
||||
|
||||
struct GD_CORE_API DuplicatedInstructionOptions {
|
||||
@@ -239,11 +238,12 @@ class GD_CORE_API PlatformExtension {
|
||||
* \param instance The "blueprint" object to be copied when a new object is
|
||||
asked for.
|
||||
*/
|
||||
gd::ObjectMetadata& AddObject(const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_,
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance);
|
||||
gd::ObjectMetadata& AddObject(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_,
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance);
|
||||
|
||||
/**
|
||||
* \brief Declare a new events based object as being part of the extension.
|
||||
@@ -253,11 +253,10 @@ class GD_CORE_API PlatformExtension {
|
||||
* \param description The user friendly description of the object
|
||||
* \param icon The icon of the object.
|
||||
*/
|
||||
gd::ObjectMetadata& AddEventsBasedObject(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_);
|
||||
gd::ObjectMetadata& AddEventsBasedObject(const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_);
|
||||
|
||||
/**
|
||||
* \brief Declare a new behavior as being part of the extension.
|
||||
@@ -420,8 +419,7 @@ class GD_CORE_API PlatformExtension {
|
||||
PlatformExtension& SetTags(const gd::String& csvTags) {
|
||||
tags.clear();
|
||||
tags = csvTags.Split(',');
|
||||
for (size_t i = 0; i < tags.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < tags.size(); i++) {
|
||||
tags[i] = tags[i].Trim().LowerCase();
|
||||
}
|
||||
return *this;
|
||||
@@ -634,31 +632,30 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
static gd::String GetNamespaceSeparator() { return "::"; }
|
||||
|
||||
static gd::String GetEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetEventsFunctionFullType(const gd::String& extensionName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String
|
||||
GetBehaviorEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetBehaviorEventsFunctionFullType(
|
||||
const gd::String& extensionName,
|
||||
const gd::String& behaviorName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String GetBehaviorFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName);
|
||||
static gd::String GetBehaviorFullType(const gd::String& extensionName,
|
||||
const gd::String& behaviorName);
|
||||
|
||||
static gd::String
|
||||
GetObjectEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName,
|
||||
const gd::String &functionName);
|
||||
|
||||
static gd::String GetObjectFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName);
|
||||
static gd::String GetObjectEventsFunctionFullType(
|
||||
const gd::String& extensionName,
|
||||
const gd::String& objectName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String GetObjectFullType(const gd::String& extensionName,
|
||||
const gd::String& objectName);
|
||||
|
||||
static gd::String GetExtensionFromFullObjectType(const gd::String& type);
|
||||
|
||||
static gd::String GetObjectNameFromFullObjectType(const gd::String& type);
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Set the namespace (the string all actions/conditions/expressions start
|
||||
* with).
|
||||
@@ -673,10 +670,10 @@ private:
|
||||
gd::String fullname; ///< Name displayed to users in the editor.
|
||||
gd::String informations; ///< Description displayed to users in the editor.
|
||||
gd::String category;
|
||||
gd::String author; ///< Author displayed to users in the editor.
|
||||
gd::String license; ///< License name displayed to users in the editor.
|
||||
bool deprecated; ///< true if the extension is deprecated and shouldn't be
|
||||
///< shown in IDE.
|
||||
gd::String author; ///< Author displayed to users in the editor.
|
||||
gd::String license; ///< License name displayed to users in the editor.
|
||||
bool deprecated; ///< true if the extension is deprecated and shouldn't be
|
||||
///< shown in IDE.
|
||||
gd::String helpPath; ///< The relative path to the help for this extension in
|
||||
///< the documentation.
|
||||
gd::String iconUrl; ///< The URL to the icon to be shown for this extension.
|
||||
|
@@ -5,6 +5,8 @@
|
||||
* project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#ifndef GDCORE_PLATFORMEXTENSION_INL
|
||||
#define GDCORE_PLATFORMEXTENSION_INL
|
||||
|
||||
@@ -36,3 +38,5 @@ gd::ObjectMetadata& PlatformExtension::AddObject(const gd::String& name,
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
|
||||
// NOLINTEND
|
@@ -337,19 +337,19 @@ struct GD_CORE_API ExpressionCompletionDescription {
|
||||
|
||||
private:
|
||||
CompletionKind completionKind;
|
||||
gd::Variable::Type variableType;
|
||||
gd::VariablesContainer::SourceType variableScope;
|
||||
gd::Variable::Type variableType = gd::Variable::Unknown;
|
||||
gd::VariablesContainer::SourceType variableScope = gd::VariablesContainer::Unknown;
|
||||
gd::String type;
|
||||
gd::String prefix;
|
||||
gd::String completion;
|
||||
size_t replacementStartPosition;
|
||||
size_t replacementEndPosition;
|
||||
size_t replacementStartPosition = 0;
|
||||
size_t replacementEndPosition = 0;
|
||||
gd::String objectName;
|
||||
gd::String behaviorName;
|
||||
bool isExact;
|
||||
bool isLastParameter;
|
||||
const gd::ParameterMetadata* parameterMetadata;
|
||||
const gd::ObjectConfiguration* objectConfiguration;
|
||||
bool isExact = false;
|
||||
bool isLastParameter = false;
|
||||
const gd::ParameterMetadata* parameterMetadata = &badParameterMetadata;
|
||||
const gd::ObjectConfiguration* objectConfiguration = &badObjectConfiguration;
|
||||
|
||||
static const gd::ParameterMetadata badParameterMetadata;
|
||||
static const gd::ObjectConfiguration badObjectConfiguration;
|
||||
|
@@ -74,8 +74,8 @@ class GD_CORE_API ExpressionsParameterMover
|
||||
|
||||
const gd::Platform &platform;
|
||||
gd::String functionName;
|
||||
std::size_t oldIndex;
|
||||
std::size_t newIndex;
|
||||
std::size_t oldIndex = 0;
|
||||
std::size_t newIndex = 0;
|
||||
gd::String behaviorType;
|
||||
gd::String objectType;
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -140,12 +140,12 @@ protected:
|
||||
|
||||
bool IsOverridingEventsBasedObjectChildrenConfiguration() const;
|
||||
|
||||
const Project* project; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
const Project* project = nullptr; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
gd::SerializerElement objectContent;
|
||||
std::unordered_set<gd::String> unfoldedChildren;
|
||||
|
||||
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
|
||||
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration = false;
|
||||
mutable std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
|
||||
|
||||
static gd::ObjectConfiguration badObjectConfiguration;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
ExternalEvents::ExternalEvents() : lastChangeTimeStamp(0) {
|
||||
ExternalEvents::ExternalEvents() {
|
||||
// ctor
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@ ExternalEvents& ExternalEvents::operator=(const ExternalEvents& rhs) {
|
||||
void ExternalEvents::Init(const ExternalEvents& externalEvents) {
|
||||
name = externalEvents.GetName();
|
||||
associatedScene = externalEvents.GetAssociatedLayout();
|
||||
lastChangeTimeStamp = externalEvents.GetLastChangeTimeStamp();
|
||||
events = externalEvents.events;
|
||||
}
|
||||
|
||||
void ExternalEvents::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", name);
|
||||
element.SetAttribute("associatedLayout", associatedScene);
|
||||
element.SetAttribute("lastChangeTimeStamp", (int)lastChangeTimeStamp);
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
@@ -41,8 +39,6 @@ void ExternalEvents::UnserializeFrom(gd::Project& project,
|
||||
name = element.GetStringAttribute("name", "", "Name");
|
||||
associatedScene =
|
||||
element.GetStringAttribute("associatedLayout", "", "AssociatedScene");
|
||||
lastChangeTimeStamp =
|
||||
element.GetIntAttribute("lastChangeTimeStamp", 0, "LastChangeTimeStamp");
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
@@ -67,24 +67,6 @@ class GD_CORE_API ExternalEvents {
|
||||
associatedScene = name_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the latest time of the build.
|
||||
* Used when the IDE found that the external events can be compiled separately
|
||||
* from scene's events.
|
||||
*
|
||||
* \todo This is specific to GD C++ Platform
|
||||
*/
|
||||
time_t GetLastChangeTimeStamp() const { return lastChangeTimeStamp; };
|
||||
|
||||
/**
|
||||
* Change the latest time of the build of the external events.
|
||||
*
|
||||
* \todo This is specific to GD C++ Platform
|
||||
*/
|
||||
void SetLastChangeTimeStamp(time_t newTimeStamp) {
|
||||
lastChangeTimeStamp = newTimeStamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the events.
|
||||
*/
|
||||
@@ -109,7 +91,6 @@ class GD_CORE_API ExternalEvents {
|
||||
private:
|
||||
gd::String name;
|
||||
gd::String associatedScene;
|
||||
time_t lastChangeTimeStamp; ///< Time of the last build
|
||||
gd::EventsList events; ///< List of events
|
||||
|
||||
/**
|
||||
@@ -119,19 +100,6 @@ class GD_CORE_API ExternalEvents {
|
||||
void Init(const ExternalEvents& externalEvents);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing ExternalEvents' name
|
||||
*/
|
||||
struct ExternalEventsHasName
|
||||
: public std::binary_function<std::unique_ptr<gd::ExternalEvents>,
|
||||
gd::String,
|
||||
bool> {
|
||||
bool operator()(const std::unique_ptr<gd::ExternalEvents>& externalEvents,
|
||||
gd::String name) const {
|
||||
return externalEvents->GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXTERNALEVENTS_H
|
||||
|
@@ -369,9 +369,9 @@ class GD_CORE_API Layout {
|
||||
private:
|
||||
gd::String name; ///< Scene name
|
||||
gd::String mangledName; ///< The scene name mangled by SceneNameMangler
|
||||
unsigned int backgroundColorR; ///< Background color Red component
|
||||
unsigned int backgroundColorG; ///< Background color Green component
|
||||
unsigned int backgroundColorB; ///< Background color Blue component
|
||||
unsigned int backgroundColorR = 0; ///< Background color Red component
|
||||
unsigned int backgroundColorG = 0; ///< Background color Green component
|
||||
unsigned int backgroundColorB = 0; ///< Background color Blue component
|
||||
gd::String title; ///< Title displayed in the window
|
||||
gd::VariablesContainer variables; ///< Variables list
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
@@ -379,12 +379,12 @@ class GD_CORE_API Layout {
|
||||
gd::LayersContainer layers;
|
||||
std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>
|
||||
behaviorsSharedData; ///< Initial shared datas of behaviors
|
||||
bool stopSoundsOnStartup; ///< True to make the scene stop all sounds at
|
||||
///< startup.
|
||||
bool standardSortMethod; ///< True to sort objects using standard sort.
|
||||
bool disableInputWhenNotFocused; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
/// focus.
|
||||
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
|
||||
///< startup.
|
||||
bool standardSortMethod = true; ///< True to sort objects using standard sort.
|
||||
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
/// focus.
|
||||
static gd::BehaviorsSharedData
|
||||
badBehaviorSharedData; ///< Null object, returned when
|
||||
///< GetBehaviorSharedData can not find the
|
||||
|
@@ -193,7 +193,7 @@ class GD_CORE_API ObjectFolderOrObject {
|
||||
static gd::ObjectFolderOrObject badObjectFolderOrObject;
|
||||
|
||||
gd::ObjectFolderOrObject*
|
||||
parent; // nullptr if root folder, points to the parent folder otherwise.
|
||||
parent = nullptr; // nullptr if root folder, points to the parent folder otherwise.
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
|
||||
// Representing an object:
|
||||
|
@@ -71,7 +71,7 @@ Project::Project()
|
||||
isPlayableWithKeyboard(false),
|
||||
isPlayableWithGamepad(false),
|
||||
isPlayableWithMobile(false),
|
||||
currentPlatform(NULL),
|
||||
currentPlatform(nullptr),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
|
@@ -990,16 +990,12 @@ class GD_CORE_API Project {
|
||||
/**
|
||||
* \brief return the objects of the project.
|
||||
*/
|
||||
gd::ObjectsContainer& GetObjects() {
|
||||
return objectsContainer;
|
||||
}
|
||||
gd::ObjectsContainer& GetObjects() { return objectsContainer; }
|
||||
|
||||
/**
|
||||
* \brief Return the objects of the project.
|
||||
*/
|
||||
const gd::ObjectsContainer& GetObjects() const {
|
||||
return objectsContainer;
|
||||
}
|
||||
const gd::ObjectsContainer& GetObjects() const { return objectsContainer; }
|
||||
///@}
|
||||
|
||||
/** \name Identifier names
|
||||
@@ -1080,32 +1076,35 @@ class GD_CORE_API Project {
|
||||
*/
|
||||
void Init(const gd::Project& project);
|
||||
|
||||
gd::String name; ///< Game name
|
||||
gd::String description; ///< Game description
|
||||
gd::String version; ///< Game version number (used for some exports)
|
||||
unsigned int windowWidth; ///< Window default width
|
||||
unsigned int windowHeight; ///< Window default height
|
||||
int maxFPS; ///< Maximum Frame Per Seconds, -1 for unlimited
|
||||
unsigned int minFPS; ///< Minimum Frame Per Seconds ( slow down game if FPS
|
||||
///< are below this number )
|
||||
bool verticalSync; ///< If true, must activate vertical synchronization.
|
||||
gd::String name; ///< Game name
|
||||
gd::String description; ///< Game description
|
||||
gd::String version; ///< Game version number (used for some exports)
|
||||
unsigned int windowWidth = 0; ///< Window default width
|
||||
unsigned int windowHeight = 0; ///< Window default height
|
||||
int maxFPS = 0; ///< Maximum Frame Per Seconds, -1 for unlimited
|
||||
unsigned int minFPS = 0; ///< Minimum Frame Per Seconds ( slow down game if
|
||||
///< FPS are below this number )
|
||||
bool verticalSync =
|
||||
false; ///< If true, must activate vertical synchronization.
|
||||
gd::String scaleMode;
|
||||
bool pixelsRounding; ///< If true, the rendering should stop pixel
|
||||
///< interpolation of rendered objects.
|
||||
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
bool pixelsRounding = false; ///< If true, the rendering should stop pixel
|
||||
///< interpolation of rendered objects.
|
||||
bool adaptGameResolutionAtRuntime =
|
||||
true; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
gd::String
|
||||
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
|
||||
///< "adaptWidth", "adaptHeight" or empty
|
||||
gd::String antialiasingMode;
|
||||
bool isAntialisingEnabledOnMobile;
|
||||
bool isAntialisingEnabledOnMobile = false;
|
||||
gd::String projectUuid; ///< UUID useful to identify the game in online
|
||||
///< services or database that would require it.
|
||||
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from
|
||||
///< events will have 0 as Z order,
|
||||
///< instead of the highest Z order
|
||||
///< found on the layer at the scene
|
||||
///< startup.
|
||||
bool useDeprecatedZeroAsDefaultZOrder =
|
||||
false; ///< If true, objects created from
|
||||
///< events will have 0 as Z order,
|
||||
///< instead of the highest Z order
|
||||
///< found on the layer at the scene
|
||||
///< startup.
|
||||
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
|
||||
gd::VariablesContainer variables; ///< Initial global variables
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
@@ -1118,7 +1117,8 @@ class GD_CORE_API Project {
|
||||
std::vector<gd::Platform*>
|
||||
platforms; ///< Pointers to the platforms this project supports.
|
||||
gd::String firstLayout;
|
||||
bool useExternalSourceFiles; ///< True if game used external source files.
|
||||
bool useExternalSourceFiles =
|
||||
false; ///< True if game used external source files.
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >
|
||||
externalSourceFiles; ///< List of external source files used.
|
||||
gd::String author; ///< Game author name, for publishing purpose.
|
||||
@@ -1127,35 +1127,40 @@ class GD_CORE_API Project {
|
||||
std::vector<gd::String>
|
||||
authorUsernames; ///< Game author usernames, from GDevelop users DB.
|
||||
std::vector<gd::String> categories; ///< Game categories
|
||||
bool isPlayableWithKeyboard; ///< The project is playable with a keyboard.
|
||||
bool isPlayableWithGamepad; ///< The project is playable with a gamepad.
|
||||
bool isPlayableWithMobile; ///< The project is playable on a mobile.
|
||||
gd::String packageName; ///< Game package name
|
||||
bool isPlayableWithKeyboard =
|
||||
false; ///< The project is playable with a keyboard.
|
||||
bool isPlayableWithGamepad =
|
||||
false; ///< The project is playable with a gamepad.
|
||||
bool isPlayableWithMobile = false; ///< The project is playable on a mobile.
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String templateSlug; ///< The slug of the template from which the game is
|
||||
///< created.
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
bool
|
||||
folderProject; ///< True if folder project, false if single file project.
|
||||
bool folderProject =
|
||||
false; ///< True if folder project, false if single file project.
|
||||
gd::String
|
||||
projectFile; ///< Path to the project file - when editing a local file.
|
||||
gd::String latestCompilationDirectory;
|
||||
gd::Platform*
|
||||
currentPlatform; ///< The platform being used to edit the project.
|
||||
gd::Platform* currentPlatform =
|
||||
nullptr; ///< The platform being used to edit the project.
|
||||
gd::PlatformSpecificAssets platformSpecificAssets;
|
||||
gd::LoadingScreen loadingScreen;
|
||||
gd::Watermark watermark;
|
||||
std::vector<std::unique_ptr<gd::ExternalEvents> >
|
||||
externalEvents; ///< List of all externals events
|
||||
ExtensionProperties
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
|
||||
mutable unsigned int gdMajorVersion; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMinorVersion; ///< The GD minor version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdBuildVersion; ///< The GD build version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMajorVersion =
|
||||
0; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMinorVersion =
|
||||
0; ///< The GD minor version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdBuildVersion =
|
||||
0; ///< The GD build version used the last
|
||||
///< time the project was saved.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -152,8 +152,8 @@ class GD_CORE_API Resource {
|
||||
gd::String metadata;
|
||||
gd::String originName;
|
||||
gd::String originIdentifier;
|
||||
bool userAdded; ///< True if the resource was added by the user, and not
|
||||
///< automatically by GDevelop.
|
||||
bool userAdded = false; ///< True if the resource was added by the user, and not
|
||||
///< automatically by GDevelop.
|
||||
|
||||
static gd::String badStr;
|
||||
};
|
||||
|
@@ -33,7 +33,7 @@ class GD_CORE_API Variable {
|
||||
Unknown,
|
||||
/** Used when objects of a group have different types for a variable. */
|
||||
MixedTypes,
|
||||
|
||||
|
||||
// Primitive types
|
||||
String,
|
||||
Number,
|
||||
@@ -393,11 +393,11 @@ class GD_CORE_API Variable {
|
||||
*/
|
||||
static Type StringAsType(const gd::String& str);
|
||||
|
||||
bool folded;
|
||||
bool folded = false;
|
||||
mutable Type type;
|
||||
mutable gd::String str;
|
||||
mutable double value;
|
||||
mutable bool boolVal;
|
||||
mutable bool boolVal = false;
|
||||
mutable bool hasMixedValues;
|
||||
mutable std::map<gd::String, std::shared_ptr<Variable>>
|
||||
children; ///< Children, when the variable is considered as a structure.
|
||||
|
@@ -187,7 +187,7 @@ class GD_CORE_API VariablesContainer {
|
||||
///@}
|
||||
|
||||
private:
|
||||
SourceType sourceType;
|
||||
SourceType sourceType = Unknown;
|
||||
std::vector<std::pair<gd::String, std::shared_ptr<gd::Variable>>> variables;
|
||||
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
|
||||
///< useful for computing changesets.
|
||||
|
@@ -456,13 +456,13 @@ class GD_CORE_API SerializerElement {
|
||||
*/
|
||||
void Init(const gd::SerializerElement &other);
|
||||
|
||||
bool valueUndefined; ///< If true, the element does not have a value.
|
||||
bool valueUndefined = true; ///< If true, the element does not have a value.
|
||||
SerializerValue elementValue;
|
||||
|
||||
std::map<gd::String, SerializerValue> attributes;
|
||||
std::vector<std::pair<gd::String, std::shared_ptr<SerializerElement> > >
|
||||
children;
|
||||
mutable bool isArray; ///< true if element is considered as an array
|
||||
mutable bool isArray = false; ///< true if element is considered as an array
|
||||
mutable gd::String arrayOf; ///< The name of the children (was useful for XML
|
||||
///< parsed elements).
|
||||
mutable gd::String deprecatedArrayOf; ///< Alternate name for children
|
||||
|
2
Core/GDCore/Serialization/rapidjson/.clang-tidy
Normal file
2
Core/GDCore/Serialization/rapidjson/.clang-tidy
Normal file
@@ -0,0 +1,2 @@
|
||||
# Disable all checks in this folder.
|
||||
Checks: '-*'
|
@@ -4,6 +4,8 @@
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -825,3 +827,5 @@ bool GD_CORE_API CaseInsensitiveEquiv( const String &lhs, const String &rhs, boo
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOLINTEND
|
||||
|
@@ -4,6 +4,8 @@
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#ifndef GDCORE_UTF8_STRING_H
|
||||
#define GDCORE_UTF8_STRING_H
|
||||
|
||||
@@ -898,3 +900,5 @@ namespace std
|
||||
* In Unicode, uppercasing/lowercasing strings to compare them in a case-insensitive way is not recommended.
|
||||
* That's why the function gd::CaseInsensitiveEquiv exists to compare two strings in a case-insensitive way.
|
||||
*/
|
||||
|
||||
// NOLINTEND
|
@@ -2,6 +2,7 @@
|
||||
#define GD_CORE_POLYMORPHICCLONE_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
|
@@ -3,6 +3,9 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#include "SystemStats.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
@@ -49,3 +52,5 @@ size_t SystemStats::GetUsedVirtualMemory() {
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
||||
// NOLINTEND
|
2
Core/GDCore/Tools/UUID/.clang-tidy
Normal file
2
Core/GDCore/Tools/UUID/.clang-tidy
Normal file
@@ -0,0 +1,2 @@
|
||||
# Disable all checks in this folder.
|
||||
Checks: '-*'
|
2
Core/GDCore/Utf8/.clang-tidy
Normal file
2
Core/GDCore/Utf8/.clang-tidy
Normal file
@@ -0,0 +1,2 @@
|
||||
# Disable all checks in this folder.
|
||||
Checks: '-*'
|
9
GDevelop.js/Bindings/prejs.js
Normal file
9
GDevelop.js/Bindings/prejs.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// If running under ASAN, disable the "container overflow" checks because of false positives
|
||||
// with std::vector<gd::String>. See https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow.
|
||||
if (Module['ASAN_OPTIONS'] === undefined)
|
||||
Module['ASAN_OPTIONS'] ='detect_container_overflow=0';
|
||||
|
||||
// Prevent calling process["exit"] when there is a abort/runtime crash
|
||||
// (useful for tests when running ASAN, to see the logs).
|
||||
if (Module.noExitRuntime === undefined)
|
||||
Module.noExitRuntime = true;
|
@@ -12,18 +12,29 @@ if(NOT EMSCRIPTEN)
|
||||
endif()
|
||||
|
||||
# Compilation flags (https://emscripten.org/docs/tools_reference/emcc.html):
|
||||
add_compile_options(-O3 -flto) # Optimizations during compilation
|
||||
# add_compile_options(-fwasm-exceptions) # Enable exceptions
|
||||
if(NOT DISABLE_EMSCRIPTEN_LINK_OPTIMIZATIONS)
|
||||
add_compile_options(-flto) # The compiler needs to know if there will be link time optimisations
|
||||
if("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "dev")
|
||||
# Development: full optimization but no link time optimization.
|
||||
add_compile_options(-O3)
|
||||
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug")
|
||||
# Debug: optimization but that will be reduced by the debugging "-g" flag.
|
||||
add_compile_options(-O3)
|
||||
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --profiling") # Debugging + profiling support
|
||||
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-assertions")
|
||||
# Debug with assertions: no optimization.
|
||||
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --profiling") # Debugging + profiling support
|
||||
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-sanitizers")
|
||||
# Debug with sanitizers: no optimization.
|
||||
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --profiling") # Debugging + profiling support
|
||||
add_compile_options(-fsanitize=address) # Uncomment to auto-detect occurences of memory bugs (memory leak, use after free, overflows, ...) - also enable linking below!
|
||||
# add_compile_options(-fsanitize=undefined) # Uncomment to auto-detect occurences of undefined behavior - also enable linking below!
|
||||
add_compile_options(-fsanitize=return) # Uncomment to auto-detect occurences of undefined behavior - also enable linking below!
|
||||
add_compile_options(-fsanitize=null) # Uncomment to auto-detect occurences of undefined behavior - also enable linking below!
|
||||
else()
|
||||
# Production: full optimization.
|
||||
# The compiler needs to know if there will be link time optimisations.
|
||||
add_compile_options(-O3 -flto)
|
||||
endif()
|
||||
|
||||
# Compiler debugging options
|
||||
#
|
||||
# add_compile_options(-fsanitize=address) # Uncomment to auto-detect occurences of memory bugs (memory leak, use after free, overflows, ...) - also enable linking below!
|
||||
# add_compile_options(-fsanitize=undefined) # Uncomment to auto-detect occurences of undefined behavior - also enable linking below!
|
||||
# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g --profiling") # Uncomment for debugging + profiling support
|
||||
# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --profiling") # Uncomment for profiling support
|
||||
# add_compile_options(-fwasm-exceptions) # Enable exceptions
|
||||
|
||||
# Common directories:
|
||||
#
|
||||
@@ -68,13 +79,10 @@ add_executable(
|
||||
"Bindings/ObjectJsImplementation.cpp"
|
||||
"Bindings/Wrapper.cpp")
|
||||
|
||||
if(DISABLE_EMSCRIPTEN_LINK_OPTIMIZATIONS)
|
||||
# Disable optimizations at linking time for much faster builds.
|
||||
message(STATUS "Disabling optimization at link time for (slightly) faster build")
|
||||
target_link_libraries(GD "-O0")
|
||||
else()
|
||||
target_link_libraries(GD "-O3 -flto")
|
||||
endif()
|
||||
|
||||
# Linker options
|
||||
#
|
||||
target_link_libraries(GD "--pre-js ${GD_base_dir}/GDevelop.js/Bindings/prejs.js")
|
||||
target_link_libraries(GD "--post-js ${GD_base_dir}/GDevelop.js/Bindings/glue.js")
|
||||
target_link_libraries(GD "--post-js ${GD_base_dir}/GDevelop.js/Bindings/postjs.js")
|
||||
target_link_libraries(GD "-s MODULARIZE=1")
|
||||
@@ -85,15 +93,32 @@ target_link_libraries(GD "-s NODEJS_CATCH_EXIT=0") # Don't print the entire GDCo
|
||||
target_link_libraries(GD "-s ERROR_ON_UNDEFINED_SYMBOLS=0")
|
||||
target_link_libraries(GD "-s \"EXPORTED_FUNCTIONS=['_free']\"")
|
||||
|
||||
# Linker debugging options
|
||||
#
|
||||
# target_link_libraries(GD "-s DEMANGLE_SUPPORT=1") # Demangle stack traces
|
||||
# target_link_libraries(GD "-s ASSERTIONS=1") # Basic runtime memory allocation checks (necessary for wasm exceptions stack traces)
|
||||
# target_link_libraries(GD "-s ASSERTIONS=2 -s SAFE_HEAP=1") # Uncomment to do runtime checks for memory allocations and access errors
|
||||
# target_link_libraries(GD "-fsanitize=address") # Uncomment to auto-detect occurences of memory bugs (memory leak, use after free, overflows, ...) - also enable compiling above!
|
||||
# target_link_libraries(GD "-fsanitize=undefined") # Uncomment to auto-detect occurences of undefined behavior - also enable compiling above!
|
||||
# target_link_libraries(--cpuprofiler) # Uncomment for interactive performance profiling
|
||||
# target_link_libraries(--memoryprofiler) # Uncomment for interactive memory profiling
|
||||
if("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "dev")
|
||||
# Disable optimizations at linking time for slightly faster builds.
|
||||
# This is safe (https://emscripten.org/docs/optimizing/Optimizing-Code.html#link-times):
|
||||
# "Note that it is ok to link with those flags even if the source files were compiled with a different optimization level"
|
||||
message(STATUS "'dev' variant: disabling optimization at link time for (slightly) faster build")
|
||||
target_link_libraries(GD "-O0")
|
||||
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug")
|
||||
message(STATUS "'debug' variant: keeping debugging information and disabling link time optimizations")
|
||||
target_link_libraries(GD "-O0")
|
||||
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-assertions")
|
||||
message(STATUS "'debug-assertions' variant: enabling Emscripten assertions and SAFE_HEAP")
|
||||
# target_link_libraries(GD "-s DEMANGLE_SUPPORT=1") # Demangle stack traces
|
||||
# target_link_libraries(GD "-s ASSERTIONS=1") # Basic runtime memory allocation checks (necessary for wasm exceptions stack traces)
|
||||
target_link_libraries(GD "-s ASSERTIONS=2 -s SAFE_HEAP=1") # Uncomment to do runtime checks for memory allocations and access errors
|
||||
# target_link_libraries(--cpuprofiler) # Uncomment for interactive performance profiling
|
||||
# target_link_libraries(--memoryprofiler) # Uncomment for interactive memory profiling
|
||||
elseif("${GDEVELOPJS_BUILD_VARIANT}" STREQUAL "debug-sanitizers")
|
||||
message(STATUS "'debug-sanitizers' variant: enabling ASAN and other sanitizers")
|
||||
target_link_libraries(GD "-fsanitize=address") # Uncomment to auto-detect occurences of memory bugs (memory leak, use after free, overflows, ...) - also enable compiling above!
|
||||
# target_link_libraries(GD "-fsanitize=undefined") # Uncomment to auto-detect occurences of undefined behavior - also enable compiling above!
|
||||
target_link_libraries(GD "-fsanitize=null") # Uncomment to auto-detect occurences of undefined behavior - also enable compiling above!
|
||||
target_link_libraries(GD "-fsanitize=return") # Uncomment to auto-detect occurences of undefined behavior - also enable compiling above!
|
||||
else()
|
||||
# Production: link time optimizations and full optimization.
|
||||
target_link_libraries(GD "-O3 -flto")
|
||||
endif()
|
||||
|
||||
# Even if we're building an "executable", prefix it by lib as it's used as a library.
|
||||
set_target_properties(GD PROPERTIES PREFIX "lib")
|
||||
|
@@ -4,9 +4,25 @@ module.exports = function (grunt) {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const isWin = /^win/.test(process.platform);
|
||||
const isDev = grunt.option('dev') || false;
|
||||
const useMinGW = grunt.option('use-MinGW') || false;
|
||||
|
||||
const possibleVariants = [
|
||||
'dev',
|
||||
'debug',
|
||||
'debug-assertions',
|
||||
'debug-sanitizers',
|
||||
];
|
||||
const variant = grunt.option('variant') || (grunt.option('dev') ? 'dev' : '');
|
||||
|
||||
if (variant && possibleVariants.indexOf(variant) === -1) {
|
||||
console.error(
|
||||
`Invalid build variant: ${variant}. Possible values are: ${possibleVariants.join(
|
||||
', '
|
||||
)}.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const buildOutputPath = '../Binaries/embuild/GDevelop.js/';
|
||||
const buildPath = '../Binaries/embuild';
|
||||
|
||||
@@ -75,9 +91,7 @@ module.exports = function (grunt) {
|
||||
...cmakeGeneratorArgs,
|
||||
'../..',
|
||||
// Disable link time optimizations for slightly faster build time.
|
||||
isDev
|
||||
? '-DDISABLE_EMSCRIPTEN_LINK_OPTIMIZATIONS=TRUE'
|
||||
: '-DDISABLE_EMSCRIPTEN_LINK_OPTIMIZATIONS=FALSE',
|
||||
variant ? '-DGDEVELOPJS_BUILD_VARIANT=' + variant : '',
|
||||
].join(' '),
|
||||
options: {
|
||||
execOptions: {
|
||||
@@ -135,7 +149,7 @@ module.exports = function (grunt) {
|
||||
cwd: __dirname,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
clean: {
|
||||
options: { force: true },
|
||||
|
@@ -39,7 +39,7 @@ These are the bindings of GDevelop core classes to WebAssembly+JavaScript. This
|
||||
npm run build # After any C++ changes.
|
||||
```
|
||||
|
||||
-> ⏱ The linking (last step) of the build can be made a few seconds faster by specifying `-- --dev`.
|
||||
> ⏱ The linking (last step) of the build can be made a few seconds faster, useful for development: `npm run build -- --variant=dev`.
|
||||
|
||||
- You can then launch GDevelop 5 that will use your build of GDevelop.js:
|
||||
|
||||
@@ -58,6 +58,18 @@ More information in [GDevelop 5 README](https://github.com/4ian/GDevelop/blob/ma
|
||||
npm test
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
||||
You can build the library with various level of debugging and memory checks.
|
||||
|
||||
```bash
|
||||
npm run build -- --variant=debug # Build with debugging information (useful for stacktraces)
|
||||
npm run build -- --variant=debug-assertions # Build with assertions and "SAFE_HEAP=1", useful to find memory bugs.
|
||||
npm run build -- --variant=debug-sanitizers # Build with memory sanitizers. Will be very slow.
|
||||
```
|
||||
|
||||
It's then recommended to run the tests (`npm test`) to check if there are any obvious memory bugs found.
|
||||
|
||||
### About the internal steps of compilation
|
||||
|
||||
The npm _build_ task:
|
||||
|
@@ -16,6 +16,7 @@
|
||||
"build": "grunt build",
|
||||
"build-with-MinGW": "grunt build --use-MinGW",
|
||||
"clean": "grunt clean",
|
||||
"lint": "node scripts/lint-with-clang-tidy.js",
|
||||
"test": "jest"
|
||||
},
|
||||
"license": "MIT",
|
||||
|
143
GDevelop.js/scripts/lint-with-clang-tidy.js
Normal file
143
GDevelop.js/scripts/lint-with-clang-tidy.js
Normal file
@@ -0,0 +1,143 @@
|
||||
const { spawn } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { makeSimplePromisePool } = require('./utils/SimplePromisePool');
|
||||
|
||||
const gdevelopRootPath = path.resolve(__dirname, '../../');
|
||||
const sourcesRootPath = path.join(gdevelopRootPath, 'Core/GDCore');
|
||||
const excludedPaths = [
|
||||
'Tools/Localization.cpp', // emscripten code which can't be linted
|
||||
'Serialization/Serializer.cpp', // Diagnostic that can't be ignored in rapidjson.
|
||||
];
|
||||
|
||||
async function findClangTidy() {
|
||||
const tryClangTidy = (clangTidyCommandName) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const process = spawn(clangTidyCommandName, ['--version'], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
process.on('error', (error) => {
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
process.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const hasClangTidy19 = await tryClangTidy('clang-tidy-19');
|
||||
if (hasClangTidy19) {
|
||||
return 'clang-tidy-19';
|
||||
}
|
||||
|
||||
const hasClangTidy = await tryClangTidy('clang-tidy');
|
||||
if (hasClangTidy) {
|
||||
return 'clang-tidy';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function runClangTidy(commandName, filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const process = spawn(
|
||||
commandName,
|
||||
[
|
||||
filePath,
|
||||
`-p=${gdevelopRootPath}/Binaries/embuild/compile_commands.json`,
|
||||
`-header-filter=".*"`,
|
||||
`--allow-no-checks`,
|
||||
`--quiet`,
|
||||
],
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
|
||||
process.on('error', (error) => {
|
||||
reject({ hasErrors: false });
|
||||
});
|
||||
|
||||
process.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve({ hasErrors: false });
|
||||
} else {
|
||||
resolve({ hasErrors: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Function to find all files in directory recursively excluding specified paths
|
||||
function findFiles(directoryPath) {
|
||||
let results = [];
|
||||
const list = fs.readdirSync(directoryPath);
|
||||
|
||||
list.forEach((file) => {
|
||||
const filePath = path.resolve(directoryPath, file);
|
||||
const relativePath = path.relative(sourcesRootPath, filePath);
|
||||
|
||||
const stat = fs.statSync(filePath);
|
||||
if (stat && stat.isDirectory() && !excludedPaths.includes(relativePath)) {
|
||||
results = results.concat(findFiles(filePath));
|
||||
} else {
|
||||
if (
|
||||
path.extname(filePath) === '.inl' ||
|
||||
path.basename(filePath) === '.gitignore' ||
|
||||
excludedPaths.includes(relativePath)
|
||||
) {
|
||||
// Ignore .inl files
|
||||
} else {
|
||||
results.push(filePath);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Main function to run clang-tidy
|
||||
async function main() {
|
||||
console.log('Checking if clang-tidy is installed and works:');
|
||||
const clangTidyCommand = await findClangTidy();
|
||||
if (!clangTidyCommand) {
|
||||
console.error(`❌ clang-tidy is not installed or not working.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const filesToCheck = findFiles(sourcesRootPath);
|
||||
|
||||
// Run clang-tidy on each file.
|
||||
const filesWithErrors = [];
|
||||
let fileIndex = 0;
|
||||
await makeSimplePromisePool(
|
||||
filesToCheck.map((filePath) => async () => {
|
||||
const { hasErrors } = await runClangTidy(clangTidyCommand, filePath);
|
||||
if (hasErrors) {
|
||||
filesWithErrors.push(filePath);
|
||||
}
|
||||
fileIndex++;
|
||||
if (fileIndex % 10 === 0) {
|
||||
console.log(
|
||||
`ℹ️ Checked ${fileIndex} out of ${filesToCheck.length} files.`
|
||||
);
|
||||
}
|
||||
}),
|
||||
30
|
||||
);
|
||||
|
||||
if (filesWithErrors.length > 0) {
|
||||
console.error(`❌ clang-tidy found errors in the following files:`);
|
||||
for (let filePath of filesWithErrors) {
|
||||
console.error(` - ${filePath}`);
|
||||
}
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log(`✅ All files passed clang-tidy checks.`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
24
GDevelop.js/scripts/utils/SimplePromisePool.js
Normal file
24
GDevelop.js/scripts/utils/SimplePromisePool.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const makeSimplePromisePool = async function (functions, n) {
|
||||
return new Promise((resolve) => {
|
||||
let inProgress = 0,
|
||||
index = 0;
|
||||
function helper() {
|
||||
// base case
|
||||
if (index >= functions.length) {
|
||||
if (inProgress === 0) resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
while (inProgress < n && index < functions.length) {
|
||||
inProgress++;
|
||||
functions[index++]().then(() => {
|
||||
inProgress--;
|
||||
helper();
|
||||
});
|
||||
}
|
||||
}
|
||||
helper();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { makeSimplePromisePool };
|
Reference in New Issue
Block a user